初阶数据结构——链表习题

news2024/10/7 7:24:39

目录

  • 如何快速调试链表习题
  • 链表习题
    • 移除链表元素
    • 链表的中间节点
    • 反转链表
    • 链表中倒数第k个结点
    • 合并两个有序链表
    • 链表分割
    • 链表的回文结构
    • 相交链表
    • 环形链表
      • slow和fast一定会相遇吗?如果fast一次走(3、4、5)步呢?
    • 环形链表 Ⅱ
      • 思路1:
      • 推论
      • 思路2:
    • 复制带随机指针的链表

如何快速调试链表习题

int main()
{
	struct ListNode* n1 = (struct ListNode*)malloc(sizeof(struct ListNode));
	assert(n1);
	struct ListNode* n2 = (struct ListNode*)malloc(sizeof(struct ListNode));
	assert(n2);
	struct ListNode* n3 = (struct ListNode*)malloc(sizeof(struct ListNode));
	assert(n3);
	struct ListNode* n4 = (struct ListNode*)malloc(sizeof(struct ListNode));
	assert(n4);
	n1->val = 7;
	n2->val = 7;
	n3->val = 7;
	n4->val = 7;

	n1->next = n2;
	n2->next = n3;
	n3->next = n4;
	n4->next = NULL;

	n1 = removeElements(n1, 7);

	return 0;
}

链表习题

移除链表元素

OJ链接
在这里插入图片描述
方法1:遇到val就删除

struct ListNode* removeElements(struct ListNode* head, int val) {
	struct ListNode* prev = NULL, * cur = head;
	while (cur)
	{
		if (cur->val == val)
		{
            if(prev==NULL)
            {
                cur=head->next;
                free(head);
                head=cur;
            }
            else
            {
                prev->next = cur->next;
			    free(cur);
			    cur = prev->next;
            }
		}
		else
		{
			prev = cur;
			cur = cur->next;
		}
	}

	return head;
}

方法2:遍历当前链表,把不是val的拿下来尾插

struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode*phead=NULL,*tail=NULL;
    while(head)
    {
        if(head->val!=val)
        {
            if(tail==NULL)
            {
                phead=tail=head;
            }
            else
            {
                tail->next=head;
                tail=tail->next;
            }
        }
        //printf("%d\n",head->val);
        head=head->next;
        if(tail)
        tail->next=NULL;
    }
    return phead;
}

链表的中间节点

OJ链接
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* middleNode(struct ListNode* head){
    struct ListNode*slow=head,*fast=head;
    while(fast && fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
    }
    return slow;
}

反转链表

OJ链接
在这里插入图片描述
在这里插入图片描述
用prev,cur,next也可以

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* reverseList(struct ListNode* head){
    if(head==NULL || head->next==NULL)
    return head;
    struct ListNode*prev=head,*cur=head->next,*next=head->next->next;
    prev->next=NULL;
    while(cur)
    {
        cur->next=prev;
        prev=cur;
        cur=next;
        if(next)
        next=next->next;
    }
    return prev;
}

链表中倒数第k个结点

OJ链接
在这里插入图片描述

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

/**
 * 
 * @param pListHead ListNode类 
 * @param k int整型 
 * @return ListNode类
 */
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode*cur=pListHead;
    struct ListNode*next=pListHead;
    while(k-- && next)
    {
        next=next->next;
    }
    if(k!=-1)
    return NULL;
    while(next!=NULL)
    {
        cur=cur->next;
        next=next->next;
    }
    //printf("%d\n\n",cur->val);
    return cur;
}

合并两个有序链表

OJ链接
在这里插入图片描述
不创建哨兵位的头节点的话:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode*head=NULL,*tail=NULL;
    if(list1==NULL)
    return list2;
    if(list2==NULL)
    return list1;
    
    while(list1 && list2)
    {
        if(list1->val>list2->val)
        {
            if(tail==NULL)
            {
                head=tail=list2;
            }
            else
            {
                tail->next=list2;
                tail=tail->next;
            }
            list2=list2->next;
        }
        else
        {
            if(tail==NULL)
            {
                head=tail=list1;
            }
            else
            {
                tail->next=list1;
                tail=tail->next;
            }
            list1=list1->next;
        }
    }
    if(list1)
    tail->next=list1;
    if(list2)
    tail->next=list2;

    return head;
}

也可以选择创建一个哨兵位的头节点来方便处理尾插

在这里插入图片描述
从图可以看出我们尾插的时候会记录尾tail,不然每次找尾效率太低,那么写单链表时为什么没有用tail呢?因为加尾指针也是有代价的,传给函数的时候就不是单单传头指针了,需要传结构体,结构体中有头指针和尾指针,结构复杂的话不利于学习链表。而且加了尾指针也只是方便了尾插,但对尾删没有帮助。

哨兵位的头节点一般不存储有效数据
有一些地方可能会用头节点存链表长度,其实是不好的,如果链表的数据类型是整形那么是好的,但当数据类型不是int,是char的时候,链表长度超过128的时候,记录的链表的长度就离谱起来了
在这里插入图片描述

当写单链表时用带哨兵位的头节点会写的更容易,不需要二级指针,因为头指针一直指向的是哨兵位,头指针的指向不需要更改了。

链表分割

OJ链接
在这里插入图片描述

思路:
在这里插入图片描述
易错点:

6的指向记得要指向NULL,否则会死循环
在这里插入图片描述
推荐使用带哨兵位的头节点,这样会方便很多

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        struct ListNode*lesshead,*lesstail,*greaterhead,*greatertail,*cur;
        lesshead=NULL;
        lesstail=NULL;
        greaterhead=NULL;
        greatertail=NULL;
        if(pHead==NULL)
        {
            return NULL;
        }
        cur=pHead;
        while(cur)
        {
            if(cur->val<x)
            {
                if(lesshead==NULL)
                {
                    lesshead=lesstail=cur;
                }
                else
                {
                    lesstail->next=cur;
                    lesstail=cur;
                }
            }
             else
            {
                if(greaterhead==NULL)
                {
                    greaterhead=greatertail=cur;
                }
                else
                {
                    greatertail->next=cur;
                    greatertail=cur;
                }
                 
            }
            cur=cur->next;
        }
        if(lesstail!=NULL)
         {
              lesstail->next=greaterhead;
         }
        if(greatertail!=NULL)
        {
        greatertail->next=NULL;
        }
        if(lesshead!=NULL)
        return lesshead;
        else
        return greaterhead;
    }
};

如果不使用带哨兵位的头节点,会有点麻烦,遇到第一个链表为空时,第二个链表为空时,尾插时都要多注意。

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        struct ListNode* headleft = pHead, * headright = pHead, * tailleft = NULL, * tailright = NULL;
    //printf("%d\n", headleft->val);
    while (pHead)
    {
        if (pHead->val < x)
        {
            if (tailleft == NULL)
            {
                headleft = tailleft = pHead;
            }
            else
            {
                tailleft->next = pHead;
                tailleft = tailleft->next;
            }
            pHead = pHead->next;
            if (tailleft)
                tailleft->next = NULL;
        }
        else
        {
            if (tailright == NULL)
            {
                headright = tailright = pHead;
            }
            else
            {
                tailright->next = pHead;
                tailright = tailright->next;
            }
            pHead = pHead->next;
            if (tailright)
                tailright->next = NULL;
        }
    }
    if (tailleft)
    {
        if(tailright)
        tailleft->next = headright;
        return headleft;
    }
    else
    {
        return headright;
    }
    }
};

链表的回文结构

OJ链接
在这里插入图片描述
思路:找中间结点,然后以中间结点为头,将后面链表逆置
注意:逆置后3是指向NULL,但2的next还是3
在这里插入图片描述

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        if(A==NULL)
        return false;
        //快慢指针找中间
        struct ListNode*slow=A,*fast=A;
        while(fast && fast->next)
        {
            slow=slow->next;
            fast=fast->next->next;
        }
        //将中间结点和后面结点逆置
        //1->2->3->2->1
        //逆置后:3中间结点的next会为NULL,2的next没有变,还是指向3
        //1->2->1->2->3
        struct ListNode*prev=NULL,*cur=slow,*next=slow->next;
        while(cur)
        {
            cur->next=prev;
            prev=cur;
            cur=next;

            if(next)
            next=next->next;
        }
        struct ListNode*head=A;
        while(prev)//不能用head作为结束条件,因为head为空时prev就会存在空指针访问
        {
            if(head->val!=prev->val)
            {
                return false;
            }
            else
            {
                head=head->next;
                prev=prev->next;
            }
        }
        return true;
    }
};

相交链表

OJ链接
在这里插入图片描述
思路:
在这里插入图片描述

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode*curA=headA,*curB=headB;
    int lenA=1;
    int lenB=1;
    while(curA->next)
    {
        curA=curA->next;
        lenA++;
    }
    while(curB->next)
    {
        curB=curB->next;
        lenB++;
    }
    if(curA!=curB)
    return NULL;

    //长链表先走差距步
    struct ListNode*longList=headA;
    struct ListNode*shortList=headB;
    if(lenB>lenA)
    {
        longList=headB;
        shortList=headA;
    }
    int gap=abs(lenA-lenB);
    while(gap--)
    {
        longList=longList->next;
    }
    while(longList!=shortList)
    {
        longList=longList->next;
        shortList=shortList->next;
    }
    return longList;
}

环形链表

OJ链接
在这里插入图片描述
思路:
fast一次走两步,slow一次走一步,fast和slow相遇,就说明存在环

bool hasCycle(struct ListNode *head) {
    struct ListNode*slow=head,*fast=head;
    while(fast && fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            return true;
        }
    }

    return false;
}

slow和fast一定会相遇吗?如果fast一次走(3、4、5)步呢?

看fast一次走几步
fast一次走两步则一定相遇
在这里插入图片描述
fast一次走三步则不一定相遇
在这里插入图片描述

环形链表 Ⅱ

OJ链接
在这里插入图片描述

思路1:

一个指针从相遇点走,一个指针从链表头开始走,他们会在入口点相遇

在这里插入图片描述

推论

在这里插入图片描述

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode*slow=head,*fast=head;
    while(fast && fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            struct ListNode*phead=head;
            while(slow!=phead)
            {
                slow=slow->next;
                phead=phead->next;
            }
            return phead;
        }
    }
    return NULL;
}

思路2:

在这里插入图片描述

复制带随机指针的链表

OJ链接
在这里插入图片描述
思路
在这里插入图片描述

struct Node* copyRandomList(struct Node* head) {
    if(head==NULL)
    {
        return NULL;
    }
	//拷贝节点到原节点的后面
    struct Node*cur=head;
    struct Node*copy=NULL;
    while(cur)
    {
        copy=(struct Node*)malloc((sizeof(struct Node)));
        copy->val=cur->val;
        
        copy->next=cur->next;
        cur->next=copy;
        cur=copy->next;
    }

    //控制拷贝节点的random使其指向原节点random的next
    cur=head;
    copy=cur->next;
    while(cur)
    {
        copy=cur->next;
        if(cur->random!=NULL)
        copy->random=cur->random->next;
        else
        copy->random=NULL;

        cur=copy->next;
    }

    //恢复原链表
    cur=head;
    struct Node*copyhead=copy,*copytail=NULL;
    while(cur)
    {
        copy=cur->next;
        if(copytail==NULL)
        {
            copytail=copyhead=copy;
        }
        else
        {
            copytail->next=copy;
            copytail=copytail->next;
        }
        cur->next=copy->next;
        cur=copy->next;
    }
    return copyhead;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/517782.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字化时代,探寻BI本质与发展趋势

可能和很多人想象的不同&#xff0c;商业智能BI虽然是信息化、数字化领域内的重要的数据类技术解决方案&#xff0c;但是商业智能BI并不是在当前时代突然冒出来的新应用&#xff0c;而是经过数十年积累的成熟产品。 早在1958年&#xff0c;IBM研究员就将商业智能BI的早期形态定…

计算卸载-论文02-计算资源差分定价

标题&#xff1a;《Differential Pricing-based Task Offloading for Delay-Sensitive IoT Applications in Mobile Edge Computing System》 期刊&#xff1a; IEEE Internet of Things Journal&#xff0c;2022 一、梳理 问题&#xff1a;在计算卸载许多场景中&#xff0c…

低代码平台:10分钟从入门到原理

导航目录 一、低代码概念 二、优势及局限 三、基础功能及搭建 1、业务流程 2、用户权限 3、统计图表 四、使用感受 五、总结 传统的软件研发方式目前并不能很好地满足企业的需求&#xff1a;人员成本高、研发时间长、运维复杂。这时低代码工具的出现为快速开发软件提供…

智慧校园平台源码 智慧班牌源码 人脸识别技术 电子班牌源码 家校互联小程序源码

智慧校园平台源码 智慧班牌源码 人脸识别技术 电子班牌源码 家校互联小程序源码 源码开发环境&#xff1a;Javaspringbootvueelement-uimysql 智慧校园系统定位于中小学教育学校&#xff0c;侧重实际应用&#xff0c;讲究实际&#xff0c;突出加强校园安全监管&#xff0c;德…

冗余-安全设计的基石

冗余构成原理就是在系统中采用2套中央处理器&#xff08;CPU&#xff09;单元&#xff0c;其中1套为工作主机&#xff0c;1套为热备&#xff0c;一旦工作主机发生故障&#xff0c;热备的CPU将自动投入工作&#xff0c;此时热备的CPU变为工作主机&#xff0c;原工作主机故障处理…

五月份了,让我看看有多少金三银四没找到工作的.....

前两天跟朋友感慨&#xff0c;去年的铜九铁十、裁员、疫情导致好多人都没拿到offer&#xff01;现在都已经5月了&#xff0c;金三银四都结束一段时间了。 金三银四都已经结束&#xff0c;大部分企业也招到了自己需要的人&#xff0c;但是我看我的读者们还是有很大一部分人在抱…

GEE:设置下载数据的Nodata值,并在ArcGIS中将空值设置为空

作者:CSDN @ _养乐多_ Google Earth Engine(GEE)是一个功能强大的云平台,用于进行地理空间数据处理和分析。它提供了丰富的数据集和工具,使得在研究和应用中使用遥感数据变得更加便捷。本文将介绍如何使用GEE设置下载的数据的Nodata值,并在ArcGIS软件中将空值设置为空,…

Golang笔记:使用标准库中os.Args和flag包编写命令行界面(CLIs)

文章目录 目的os.ArgsflagFlagSet总结 目的 命令行界面&#xff08;Command-line Interfaces&#xff09;是比较常用的一种软件形式。对于大部分开发运维人员来说很多时候CLIs可能比图形界面更加方便。软件开发时也经常会有需要开发命令行界面形式软件的情况&#xff0c;使用G…

栈和队列:理解与使用

目录 栈 顺序栈结构 链式栈结构 中缀表达式和后缀表达式 顺序栈四则运算 链式栈四则运算 队列 顺序队列结构 链式队列结构 总结 栈和队列是计算机科学中常见的数据结构&#xff0c;它们都是一种线性数据结构&#xff0c;可以对元素进行快速的插入、删除和查找操作。栈…

00后工资太低,现在转行数据分析还能就业吗?,求大佬指点!

当然可以就业&#xff0c;只要专业技能过关。IT是靠技术吃饭的行业&#xff0c;没有复杂的人际关系和面子工程&#xff0c;相对其他行业要纯粹一些。当然&#xff0c;如果你技术不过关&#xff0c;或者跟不上技术更新发展速度&#xff0c;淘汰也是必然的&#xff0c;IT行业不能…

听我一句劝,千万别去外包,两年外包生涯做完,感觉自己废了一半....

先说一下自己的情况。大专生&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近5年的点点点&#xff0c;今年年上旬&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01;而我已经在一个企业干了五年的功能测试…

前端开发和测试的新伙伴:Requestly,让你事半功倍!

目录 引言 痛点 前端测试 后端测试 曾使用的应对措施 Charles Chrome 插件 实现mock工具 Requestly Requestly的功能 流量捕捉方式 请求的修改 响应的修改 请求响应录制 我对Requestly的应用 总结 引言 想必每个前端开发和测试的小伙伴都曾经历过不断地切换页…

CV界的chatgpt出现——Segment Anything能分割万物

目录 一、前言&#xff08;1&#xff09;弱人工智能&#xff08;Weak AI&#xff09;&#xff08;2&#xff09;强人工智能&#xff08;General AI&#xff09;&#xff08;3&#xff09;超人工智能&#xff08;Super AI&#xff09; 二、SAM的一些介绍2.1 模型的结构是什么&am…

React动态路由配置

目录 项目初始化 模块创建 统一导出 全局模块配置选项 核心代码 使用及效果展示 博文适用于react-router v6及以上&#xff0c;其中还有很多值得改进的地方 最近学习react的过程中&#xff0c;思考怎样实现动态路由的配置(最终实现从页面配置最终动态从数据库加载上线模…

C++解析JSON JSONCPP库的使用

首先去GitHub下载JSONCPP的源码&#xff1a; JSonCpp的源码 解压后得到&#xff1a;jsoncpp-master 文件夹 需要的是&#xff1a;jsoncpp-master\src\lib_json 目录下的所有文件和 jsoncpp-master\include\json 目录下的所有文件&#xff0c;在MFC工程目录下新建两个文件夹或…

承诺协议:定义 构造

文章目录 安全性定义方案构造基于 OWP 存在性基于 DL 假设基于 OWF 存在性基于 DDH 假设 总结 安全性定义 承诺协议&#xff08;Commitment Scheme&#xff09;是一个两阶段的两方协议。一方是承诺者&#xff08;Committer&#xff09; C C C&#xff0c;另一方是接收者&#…

网络安全怎么学?

一、怎么入门&#xff1f; 这个 Web 安全学习路线&#xff0c;整体大概半年左右&#xff0c;具体视每个人的情况而定。 &#xff08;上传一直很模糊&#xff0c;所以就没有展开了&#xff0c;需要高清版的可以在下面领取&#xff09; &#x1f449; 【一学习路线高清版一】&a…

WiFi(Wireless Fidelity)基础(八)

目录 一、基本介绍&#xff08;Introduction&#xff09; 二、进化发展&#xff08;Evolution&#xff09; 三、PHY帧&#xff08;&#xff08;PHY Frame &#xff09; 四、MAC帧&#xff08;MAC Frame &#xff09; 五、协议&#xff08;Protocol&#xff09; 六、安全&#x…

AndroidStudio-学习笔记之多级目录功能的设计与开发

多级目录功能的设计与开发 演示效果需求描述开发预计前端后端 前端开发多级目录的UI小框架前端xml前端代码---本地demo版前端代码---服务器版逻辑说明 后端开发表设计书写接口 演示效果 需求描述 根据需求&#xff0c;为用户展示多级目录(目前设计的为4级目录)&#xff0c;并在…

Win10笔记本无法正常启动代码0xc0000001解决方法

Win10笔记本无法正常启动代码0xc0000001解决方法。最近不少的用户在笔记本电脑安装Win10系统使用时&#xff0c;出现了蓝屏的情况&#xff0c;电脑显示错误代码0xc0000001无法启动到桌面使用。那么这个情况怎么去进行问题的解决呢&#xff1f;来看看以下的解决方法吧。 准备工作…