小结 | C 单链表操作 (上)

来源:互联网 发布:双十一淘宝商家多发货 编辑:程序博客网 时间:2024/06/06 08:53

零、声明

typedef int DataType;typedef struct ListNode{    DataType data;    struct ListNode* next;}ListNode;

一、从尾到头打印单链表

利用递归的思想,在遇到尾节点之前不返回。

void PrintTailFront(ListNode *list){    if (list == NULL)    {        return;    }    PrintTailFront(list->next);    printf("%d ", list->data);}

二、删除一个无头单链表的非尾节点

不知道头结点的话,就无法知道需要删除的节点的前一个节点。但是我们知道删除节点的下一个节点,通过将后一个节点的值赋给当前节点的方式,可以实现删除的效果。
这里写图片描述

void DeleteNoneHeadPos(ListNode *pos){    ListNode *Next == NULL;    if (pos == NULL)    {        printf("Can not find the position\n");        return;    }    Next = pos->next;    pos->data = Next->data;    pos->next = Next->next;    free(Next);}

三、在无头单链表的一个节点前插入一个节点

跟上一个一样,不知道前一个节点的位置。所以就生成一个新节点,将节点链接到当前节点的后面,再交换两者的值。
这里写图片描述

void InsertNoneHead(ListNode *pos, DataType x){    ListNode *New = BuyList(x);    DataType tmp = 0;    if (pos == NULL)    {        printf("Can not find the position\n");        return;    }    tmp = New->data;    New->data = pos->data;    pos->data = tmp;    New->next = pos->next;    pos->next = New;}

BuyList(DataType x)

//生成新的节点ListNode *BuyList(DataType x){    ListNode *Node = (ListNode *)malloc(sizeof(ListNode));    if (Node == NULL)    {        printf("Failure to malloc Node\n");        return 0;    }    Node->data = x;    Node->next = NULL;    return Node;}

四、单链表实现约瑟夫环

约瑟夫环问题(百度百科),该单链表是头尾相接的环。

DataType JosephRing(ListNode *list, DataType num){    ListNode *Next;    DataType tmp = 0;    if (list == NULL)    {        printf("There are not any data\n");        return -1;    }    //循环结束至只有一个    while (list->next != list)    {        tmp = num;        //一次循环走的次数        while (tmp--)        {            list = list->next;        }        //删除节点        Next = list->next;        list->data = Next->data;        list->next = Next->next;        free(Next);    }    return list->data;}

五、逆置 / 反转单链表

几个特殊的点:
1、为空、只有一个节点,直接返回
2、Next = Next - >next 为NULL 的时候,注意判断 Next = Next - >next -> next 是否为空
3、最后需要将头结点重新赋值,指向新的头节点。

这里写图片描述

这里写图片描述

这里写图片描述

void ReverseList(ListNode **pHead){    ListNode *Next = NULL;    ListNode *pre = NULL;    if (*pHead == NULL)    {        printf("The list is empty \n");        return;    }    if ((*pHead)->next == NULL)    {        return;    }    Next = (*pHead)->next;    while (*pHead)    {        (*pHead)->next = pre;        pre = (*pHead);        (*pHead) = Next;        //避免 Next->next->next == NULL访问出错        if (Next != NULL)        {            Next = Next->next;        }    }    //头结点赋值    *pHead = pre;}

六、单链表排序(冒泡排序)

几个注意的点:
1、需要一个尾指针指向尾部,并每遍历一次就向前回退一个节点
2、用两个指针来移动,并交换
3、一趟结束的标志是尾指针和当前指针地址相同
4、停止的判断条件需要小心
5、可以优化,当有一趟中,并没有交换任何数据,就可以结束排序。

void BubbleSort(ListNode *list){    ListNode *Next = NULL;    ListNode *cur = list;    ListNode *tail = list;    DataType tmp = 0;    DataType flag = 0;    if (list == NULL || list->next == NULL)    {        return;    }     //移动 tail 指向尾部 NULL    while (tail)    {        tail = tail->next;    }    //判断两指针还未相遇    while (cur != tail)    {        //将pre指向头结点,cur指向第二个结点        Next = cur->next;        //cur->next 在 tail 时候停止        while (cur->next != tail)        {            if (cur->data > Next->data)            {                flag = 1;                tmp = Next->data;                Next->data = cur->data;                cur->data = tmp;            }            cur = Next;            Next = Next->next;        }        if(flag == 0)            break;        tail = cur;        cur = list;    }}

七、合并两个有序链表, 合并后依然有序

思路:
1、用一个新的头指针,一个尾指针用来记录尾部的位置
2、比较两个有序链表,小的值赋给新的头结点
3、有了第一个节点之后,利用循环,在尾插的方式下依次按大小插入
4、当其中一个链表为空之后,可以直接将另一个链表剩下的节点直接插入至尾部

ListNode* MergeList(ListNode *L1, ListNode *L2){    ListNode *New = NULL;    ListNode *Tail = NULL;    //判断是否为空    if (L1 == NULL)    {        return L2;    }    if (L2 == NULL)    {        return L1;    }    //设置第一个节点    if (L1->data < L2->data)    {        New = L1;        L1 = L1->next;    }    else    {        New = L2;        L2 = L2->next;    }    //利用循环对节点向后赋值    Tail = New;    while (L1 && L2)    {        if (L1->data > L2->data)        {            Tail->next = L2;            L2 = L2->next;        }        else        {            Tail->next = L1;            L1 = L1->next;        }        Tail = Tail->next;    }    //如果有还未链接的节点,直接链接到尾指针后面    if (L1)    {        Tail->next = L1;    }    if (L2)    {        Tail->next = L2;    }    return New;}

八、查找单链表的中间节点,要求只能遍历一次链表

思想:
1、利用快慢指针,慢指针走一步,快指针走两步。
2、如果节点的个数是奇数,循环结束判断条件是 Fast->next == NULL
3、如果节点的个数是偶数,循环结束判断条件是 Fast->next ->next== NULL,同时返回两个中间节点的第一个

这里写图片描述

ListNode *FindMid(ListNode *list){    ListNode *Slow = list;    ListNode *Fast = list;    if (list == NULL)    {        return NULL;    }    if (list->next == NULL)    {        return list;    }    //循环判断,奇数和偶数    while (Fast->next && Fast->next->next)    {        Slow = Slow->next;        Fast = Fast->next->next;    }    return Slow;}

九、查找单链表的倒数第k个节点,要求只能遍历一次链表

思想:
1、跟上面一样,快指针先走K步,然后快慢指针一起走
2、判断的是,链表中是否有K个节点

ListNode *FindKNode(ListNode *list,DataType k){    ListNode *Slow = list;    ListNode *Fast = list;    if (list == NULL)    {        return list;    }    //判断是否有K个节点,同时Fast指针先走K步    while (k--)    {        Fast = Fast->next;        if (Fast == NULL)        {            return NULL;        }    }    //快慢指针一起走    while (Fast)    {        Slow = Slow->next;        Fast = Fast->next;    }    return Slow;}

没了

原创粉丝点击