单链表(包含反转、导出、循环链表思路)

生活永远是自己的,美哉美哉。实习告一段落,大学也算彻底结束,就像毛不易唱的二零三,给我想要的自由。
最近学习汇编及数据结构(C语言),链表也总算告一段落,本篇是单链表的学习代码笔记,本来也想想每一步都做图,分享知识,让更多的朋友去学习,但是本人局限于能力,图片无法表达自己想要的描述,所以干脆不做图了。
随后日子会有双链表的操作,后面仍然会分享栈、队列的自学笔记,也可能写汇编8086的心得,希望大家一起共勉。
代码可能有些繁琐(很多地方都可以优化),只是新手 给 新手的一些参考

反转链表用的迭代思路参考(引用):https://blog.csdn.net/blioo/article/details/62050967
作者:blioo
本人感觉引用文章思路非常好,适合初学者,推荐给大家,下面贴自己的学习心得:

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

typedef struct Node
{
    int data;
    struct Node *next;
}Node,*PNode;

PNode ControlLinkList(PNode PHead, int len);                         //控制函数
PNode CreateLinkList(void);                                                  //构造链表
int TraverseLinkList(PNode PHead);                                      //遍历链表,返回链表长度len
void GetInfo(PNode PNew, int i);                                              //用户信息输入,当输入代码量大的时候封装起来
void InsertLinkList(PNode PHead, int pos, int data, int len);       //插入某节点
void FindLinkList(PNode PHead, int pos);                                    //寻找某节点
void DeleteLinkList(PNode PHead, int pos);                             //删除某节点
void ModifyLinkList(PNode PHead, int pos, int data);                //修改某数据
void ExportLinkList(PNode PHead);                                             //导出链表(或导出某节点之前、之后的数据稍加修改即可)
PNode ReverseLinkList(PNode PHead);                                    //逆转链表
void ReleaseLinkList(PNode PHead);                                         //释放链表

int main(void)
{
    PNode PHead = CreateLinkList();
    int len = TraverseLinkList(PHead);
    ControlLinkList(PHead,len);
    return 0;
}

PNode ControlLinkList(PNode PHead, int len)
{
    int pos;
    int data = 0;
    printf("请输入插入的节点pos:\n");
    scanf("%d",&pos);
    printf("请输入插入的数据data:\n");
    scanf("%d",&data);
    InsertLinkList(PHead, pos, data, len);
    TraverseLinkList(PHead);
    printf("请输入查询的节点: ");
    scanf("%d",&pos);
    FindLinkList(PHead, pos);
    printf("请输入删除的节点: ");
    scanf("%d",&pos);
    DeleteLinkList(PHead, pos);
    TraverseLinkList(PHead);
    printf("请输入修改的节点: ");
    scanf("%d",&pos);
    printf("请输入修改的数据: ");
    scanf("%d",&data);
    ModifyLinkList(PHead, pos, data);
    TraverseLinkList(PHead);
    ReverseLinkList(PHead);
    TraverseLinkList(PHead);
    ReleaseLinkList(PHead);
    return PHead;
}

void GetInfo(PNode PNew, int i)
{
    printf("请输入 No.%d Data = ",i+1);
    scanf("%d",&PNew->data);
}

PNode CreateLinkList(void)
{
    int i;
    int len = 0;
    PNode PHead = (PNode)malloc(sizeof(Node));
    PNode PTail = PHead;
    if( NULL == PHead )
    {
        printf("内存分配失败\n");
        exit(EXIT_FAILURE);
    }

    PTail->next = NULL;
    printf("请输入节点个数: ");
    scanf("%d",&len);

    for( i = 0; i < len; i++ )
    {
        PNode PNew = (PNode)malloc(sizeof(Node));
        if( NULL == PNew )
        {
            printf("内存分配失败\n");
            exit(EXIT_FAILURE);
        }
        GetInfo(PNew, i);
        PTail->next = PNew;
        PNew->next = NULL;
        PTail = PNew;
    }
    printf("共%d个链表创建成功\n",i+1);
    return PHead;
}

int TraverseLinkList(PNode PHead)
{
    int len = 0;
    PNode p = PHead->next;
    while( NULL != p)
    {
        len++;
        printf("No.%d Data = %d\n",len,p->data);
        p = p->next;
    }
    printf("遍历完成\n");
    return len;
}

void InsertLinkList(PNode PHead, int pos, int data, int len)
{
    int i = 0;
    PNode p = PHead->next;
    if( NULL != p )
    {
        PNode PNew = (PNode)malloc(sizeof(Node));
        if( NULL == PNew )
        {
            printf("分配内存失败");
            exit(EXIT_FAILURE);
        }
//      printf("LEN = %d\n",len);
        if( 0 != pos-1 )
        {
            int l = 1;                                        //为了弥补i从0开始
            while( l < pos-1 )                          //中间插法
            {
                l++;
                p = p->next;
            }
            PNew->data = data;
            PNew->next = p->next;
            p->next = PNew;
        }
        /*
        else if( pos > len && 0 != pos-1 )              //插入链表尾
        {
            while( i < len )
            {
                i++;
                p = p->next;
            }
            p->next = PNew;                                    //最后一个p节点指向NULL
            PNew->data = data;
            PNew->next = NULL;
        }
        */
        else
        {
            PHead->next = PNew;                         //插入链表头
            PNew->data = data;
            PNew->next = p;
        }
    }
    else
    {
        printf("空链表\n");
    }
}

void FindLinkList(PNode PHead, int pos)
{
    int i = 0;
    PNode p = PHead->next;
    if( NULL != p )
    {
        while( i < pos-1 )
        {
            i++;
            p = p->next;
        }
        printf("查找元素成功,数据如下:\n");
        printf("No.%d Data = %d\n",i+1,p->data);
    }
    else
    {
        printf("链表为空\n");
    }
}   

void DeleteLinkList(PNode PHead, int pos)
{
    int i = 0;
    PNode p = PHead->next;
    PNode PTemp;
    while( NULL != p && i != (pos-1) )
    {
        i++;
        p = p->next;
    }
    PTemp = p->next;
    p->next = p->next->next;
    free(PTemp);
    PTemp = NULL;
    printf("删除节点成功\n");

}

void ModifyLinkList(PNode PHead, int pos, int data)
{
    int i = 0;
    PNode p = PHead->next;
    while( NULL != p && i != pos-1 )                               //一般用这种方式来判空与循环代码简洁
    {
        i++;
        p = p->next;
    }
    p->data = data;
    printf("修改数据成功:\n");
    printf("No.%d  Data = %d\n\n",i,p->data);
}

void ExportLinkList(PNode PHead)
{
    FILE *fp;
    PNode p = PHead->next;

    if( (fp = fopen("LinkList.txt","ab")) == NULL )
    {
        printf("读取文件失败,创建文件成功");
        exit(EXIT_FAILURE);
    }

    while( NULL != p )
    {
        fputc(p->data,fp);
        p = p->next;
    }

    printf("导出成功");
    fclose(fp);
}

PNode ReverseLinkList(PNode PHead)
{
    PNode q = NULL;                     //作为反转节点
    PNode Ptemp = NULL;             //建立新节点指向下一个
    PNode p = PHead->next;          //指向第一个链表数据
    PHead->next = NULL;             //头结点为空
    while( NULL != p )
    {
        Ptemp = p->next;                    //下一个节点
        p->next = q;                         //指向反转节点
        q = p;                                    //q指向前一个节点p  q->next = p;
        p = Ptemp;                          //p接着去下一个节点
    }
    PHead->next = q;                    //头结点指向翻转后的链表
    printf("链表翻转成功\n");
    return PHead;
}

void ReleaseLinkList(PNode PHead)
{
    PNode p = PHead->next;
    PNode temp;
    PHead->next = NULL;
    free(PHead);
    while( NULL != p )
    {

        temp = p->next;
        free(p);
        p = temp;
    }
    free(temp);
    printf("释放成功!\n");
}

代码在window7 64 VC++6.0编译通过粘贴,代码可能缩进有些不好看。
下面说一说循环单链表思路,姑且以我的认识和实际的应用,就是就体现在循环的不同。
在创建单链表的时候,最后把PNew->next = NULL 改为 PNew->next = PHead;
这里PHead是头结构体指针,所以->next才是指向第一个数据。
循环单链表,PHead可以从链表任意节点开始遍历都可以遍历整个链表。
注意:循环条件不可以是while( NULL !=p ),因为循环链表没有NULL值,进入死循环了就。
头尾相连,遍历条件应该改为 while( PHead != p ),头不等于p不就解决了。

原文地址:http://blog.51cto.com/13352079/2126869

时间: 2024-10-17 00:44:03

单链表(包含反转、导出、循环链表思路)的相关文章

用两种递归思路与循环实现单链表的反转

typedef struct ListNode{ int data; struct ListNode *next; }ListNode; //递归一 ListNode *ReverseList (ListNode *pHead, ListNode *nHead = NULL) { //每次取下第一个节点头插法创建新链表 //nHead为反转后链表的头节点 if(pHead == NULL) return NULL; ListNode *pNext = pHead -> next; pHead -

[算法]实现单链表的反转

实现链表的反转 解题思路: 为了正确反转一个链表,需要调整指针的指向.举例说明,例如i,m,n是三个相邻的结点,假设经过若干步操作,已经把结点i之前的指针调整完毕,这些结点的next指针都指向前面一个结点.现在遍历到结点m,当然需要调整结点的next指针,让它指向结点i,但需要注意的是,一旦调整了指针的指向,链表就断开了,因为已经没有指针指向结点n,没有办法再遍历到结点n了,所以为了避免指针断开,需要在调整m的next之前要把n保存下来.接下来试着找到反转后链表的头结点.不难分析出翻转后链表的头

秒懂单链表及其反转(reverse)

什么是链表,这种数据结构是由一组Node组成的,这群Node一起表示了一个序列.链表是最普通,最简单的数据结构,它是实现其他数据结构如stack, queue等的基础. 链表比起数组来,更易于插入,删除. Node可以定义如下: typedef int element_type; typedef struct node *node_ptr; struct node { element_type element; node_ptr next; }; 另外关于要不要头节点这个问题,我建议加上头节点,

单链表的反转

如何把一个单链表进行反转? 方法1:将单链表储存为数组,然后按照数组的索引逆序进行反转. 方法2:使用3个指针遍历单链表,逐个链接点交替使用指针改变链表的指向进行反转. 方法3:从第3个节点到第N-1个节点,依次逐节点插入到第1个节点(head节点)之后,再将第N个节点指向head(成环),然后将此时head的下一个节点设为head,最后将原head指向NULL. 方法4:   递归(没搞懂~) 方法2: ActList* ReverseList2(ActList* head) {   //Ac

单链表的反转问题

单链表的反转问题 单链表反转问题经常会遇到.在此记录一下,以便查阅方便. 如果反转一个有头结点的使用下面的方法比较合适. //反转单链表,此单链表带有头节点. //思想:使用tmp临时指针保存头结点与链表的关系 typedef struct ListNode  { int data; struct ListNode * next; }ListNode,*LinkList; void ReverseList(ListNode* Head) { ListNode *current,*tmp; cur

看图理解单链表的反转

如何把一个单链表进行反转? 方法1:将单链表储存为数组,然后按照数组的索引逆序进行反转. 方法2:使用3个指针遍历单链表,逐个链接点进行反转. 方法3:从第2个节点到第N个节点,依次逐节点插入到第1个节点(head节点)之后,最后将第一个节点挪到新表的表尾. 方法4:   递归(相信我们都熟悉的一点是,对于树的大部分问题,基本可以考虑用递归来解决.但是我们不太熟悉的一点是,对于单链表的一些问题,也可以使用递归.可以认为单链表是一颗永远只有左(右)子树的树,因此可以考虑用递归来解决.或者说,因为单

单链表,双向链表,循环链表

数据结构: 定义: 特定的数据类型(个体)和特定的存储结构(个体的关系) 数据如何存储在内存中 分类: 线性结构: 数据元素之间存在一对一的线性关系.线性结构拥有两种不同的存储结构,即顺序存储结构和链式存储结构. 数组与列表:顺序存储结构 相同点: 需要申请一块连续的内存空间 不同点: 列表或者数组中的元素是如何存储的,以及两者的区别? 在其他语言中(C/C++)数组申请的内存空间是一定的, 比如申请10M的内存空间,如果数据超过10M会溢出,需要手动申请和释放 在python中不会出现溢出报错

单链表的反转 python实现实例

单链表反转实现 1.递归实现 根据递归,递归到最后一个节点(条件为head3为非空,其下一个指向为空),将其next指向前一个结点,前一个结点的指向为None. def recurse(head, newhead): # 递归,head为原链表的头结点,newhead为反转后链表的头结点 if head is None: return if head.next is None: newhead = head else: newhead = recurse(head.next, newhead)

线性表总结(单链表的反转)

主要总结单链表反转的几种方法 第一种方法貌似是递归,不太懂,第二种方法使用三个指针逐一完成逆置 结构体定义:class ListNode { int val; ListNode next; ListNode(int x) { //这步没看懂,是结构体里引用了自己吗 val = x; next = null; } } 1 // 1.就地反转法 2 public ListNode reverseList1(ListNode head) { 3 if (head == null) 4 return h

单链表的反转非递归算法

定义单链表的结点 typedef struct ListNode{ int value; ListNode *next; }ListNode; 我们采用的单链表是带头结点的. 需要遍历一遍链表,在遍历过程中,把遍历的节点一次插入到头部.在这个过程之后,第一个节点成了最后节点,因此要特殊处理,改其后继为NULL. void Inversion(ListNode* head) { if(head->next == NULL) return; //带头结点的单链表,当单链表为空时 if(head->