【数据结构初阶】单链表经典算法题十二道——得道飞升(上篇)

目录

1、移除元素

2、反转链表

3、链表的中间节点

4、合并两个有序链表

[Relaxing Time!!!](#Relaxing Time!!!)

[------------------------------------------------ 天气之子·幻 ------------------------------------------------](#———————————————— 天气之子·幻 ————————————————)


1、移除元素

思路:

创建一个新链表(newhead,newtail),遍历原链表,把不等于 val 的结点尾插到新链表中。

cs 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
    //创建新链表
    ListNode* newhead;ListNode* newtail;
    newhead=newtail=NULL;
    //遍历数组
    ListNode* pcur=head;
    while(pcur)
    {
        if(pcur->val!=val)
        {
            //又分两种情况,链表为空,不为空
            if(newhead==NULL)
            {
                newtail=newhead=pcur;
            }
            else
            {
                newtail->next=pcur;
                newtail=newtail->next;
            }
        }
        pcur=pcur->next;
    }
    //[7,7,7,7,7],val=7 ,这种情况下,newtail=NULL,newtail->next=NULL,此时newtail不能解引用,所以加上if条件
    if(newtail)               
        newtail->next=NULL;
    return newhead;
}

注意:

当原链表为空时,newhead = newtail = pcur;

在实例中,最后一个5结点被尾插到新链表中时,5结点的next指针指向的仍然是后面的6结点,所以最后返回的时候结果里面含有6,所以我们把最后一个等于val结点的next指针指向NULL即可!

2、反转链表

新奇思路:

cs 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {
    //链表也有可能是空链表
    if(head==NULL)
    {
        return head;
    }
    //定义三个指针变量
    ListNode* n1,*n2,*n3;
    n1=NULL;n2=head;n3=n2->next;
    while(n2)
    {
        n2->next=n1;
        n1=n2;
        n2=n3;
        if(n3)
        n3=n3->next;
    }
    return n1;
}

3、链表的中间节点

思路:

奇数个结点

偶数个结点

cs 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
    ListNode* slow=head;
    ListNode* fast=head;

    //while(fast->next&&fast)错误,不可互换顺序,当为偶数个结点时,fast==NULL循环结束,但是while
      循环内会先判断fast->next,空指针不能解引用,会报错

    while(fast&&fast->next)
    {
        //慢指针每次走一步
        //快指针每次走两步
        slow=slow->next;
        fast=fast->next->next;
    }
    //此时slow指向的结点恰好是中间结点
    return slow;
}

快慢指针为什么可以找到中间结点?(快慢指针的原理)

慢指针每次走一步,快指针每次走两步,当快指针走到链表的尾结点时,假设链表的长度为n,快指针走的路程是慢指针的两倍,2*慢=快,即慢指针走的路程是n/2。

4、合并两个有序链表

思路:

创建一个新链表,newhead,newtail 指向新链表的头结点,定义两个指针分别指向原链表的头结点,两个指针指向的数据比较大小,谁小谁尾插到新链表里面。思路清晰,不过要注意很多细节,直接上代码:

cs 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {

    //处理原链表为空链表的情况
    if(list1==NULL)
    {
        return list2;
    }
    if(list2==NULL)
    {
        return list1;
    }

    //创建一个新链表
    ListNode* newhead=NULL;
    ListNode* newtail=NULL;

    //创建两个指针分别指向两个链表的头结点来遍历原链表
    ListNode* l1=list1;
    ListNode* l2=list2;
    
    while(l1&&l2)
    {
        if(l1->val<l2->val)
        {
            //l1尾插到新链表
            if(newtail==NULL)
            {
                newtail=newhead=l1;
            }
            else
            {
                newtail->next=l1;
                newtail=newtail->next;
            }
            l1=l1->next;
        }
        else
        {
            //l2尾插到新链表
            if(newhead==NULL)
            {
                newtail=newhead=l2;
            }
            else
            {
                newtail->next=l2;
                newtail=newtail->next;
            }
             l2=l2->next;
        }
    }
    //出循环,要么l1==NULL,要么l2==NULL
        if(l1)
            newtail->next=l1;  想想这里为啥不用while循环?
        if(l2)
            newtail->next=l2;
    return newhead;
}
cs 复制代码
//优化过后,申请一个不为空的链表,就无需再判断新链表是否为空,最后不要忘记free
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {

    //链表为空的情况
    if(list1==NULL)
    {
        return list2;
    }
    if(list2==NULL)
    {
        return list1;
    }
    
    //创建一个新链表
    ListNode* newhead,*newtail;
     newhead=newtail=(ListNode*)malloc(sizeof(ListNode));
    //定义两个指针来遍历数组
    ListNode* l1=list1;
    ListNode* l2=list2;

    while(l1&&l2)
    {
        if(l1->val<l2->val)
        {
            newtail->next=l1;
            l1=l1->next;
            newtail=newtail->next;
        }
        else
        {
            newtail->next=l2;
            l2=l2->next;
            newtail=newtail->next;
        }
    }
    if(l1)
        newtail->next=l1;
    if(l2)
        newtail->next=l2;

    ListNode* ret=newhead->next;
    free(newhead);
    newhead=NULL;
    return ret;
    
}

完---

Relaxing Time!!!

------------------------------------------------ 天气之子·幻 ------------------------------------------------

天气之子·幻_TypeD_高音质在线试听_天气之子·幻歌词|歌曲下载_酷狗音乐酷狗音乐为您提供由TypeD演唱的高清音质无损天气之子·幻mp3在线听,听天气之子·幻,只来酷狗音乐!https://t4.kugou.com/song.html?id=b43Kh7aCPV2

至此结束------

再见------

相关推荐
cuisidong199715 分钟前
5G学习笔记三之物理层、数据链路层、RRC层协议
笔记·学习·5g
乌恩大侠17 分钟前
5G周边知识笔记
笔记·5g
小刘|20 分钟前
《Java 实现希尔排序:原理剖析与代码详解》
java·算法·排序算法
jjyangyou25 分钟前
物联网核心安全系列——物联网安全需求
物联网·算法·安全·嵌入式·产品经理·硬件·产品设计
van叶~42 分钟前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
简简单单做算法42 分钟前
基于Retinex算法的图像去雾matlab仿真
算法·matlab·图像去雾·retinex
云卓SKYDROID1 小时前
除草机器人算法以及技术详解!
算法·机器人·科普·高科技·云卓科技·算法技术
半盏茶香1 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
徐子童1 小时前
双指针算法习题解答
算法
咔叽布吉2 小时前
【论文阅读笔记】CamoFormer: Masked Separable Attention for Camouflaged Object Detection
论文阅读·笔记·目标检测