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

目录

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

至此结束------

再见------

相关推荐
2301_764441332 小时前
Python构建输入法应用
开发语言·python·算法
love530love2 小时前
【笔记】ComfUI RIFEInterpolation 节点缺失问题(cupy CUDA 安装)解决方案
人工智能·windows·笔记·python·插件·comfyui
愚戏师2 小时前
MySQL 数据导出
数据库·笔记·mysql
AI科技星2 小时前
为什么变化的电磁场才产生引力场?—— 统一场论揭示的时空动力学本质
数据结构·人工智能·经验分享·算法·计算机视觉
摇滚侠2 小时前
2025最新 SpringCloud 教程,教程简介,笔记01
笔记·spring cloud
TheLegendMe3 小时前
贪心+线程安全单例
算法·哈希算法
豐儀麟阁贵3 小时前
8.5在方法中抛出异常
java·开发语言·前端·算法
胖咕噜的稞达鸭3 小时前
算法入门:滑动窗口--->找到字符串中所有的字母异位词,串联所有的子串,最小覆盖子串
数据库·redis·算法
小青龙emmm4 小时前
2025级C语言第二次周测(国教专用)题解
c语言·开发语言·算法
一起养小猫4 小时前
《Java数据结构与算法》第三篇(下)队列全解析:从基础概念到高级应用
java·开发语言·数据结构