数据结构——链表专题1

文章目录

  • 一、移除链表元素
  • 二、反转链表
  • 三、合并两个有序链表
  • 四、链表的中间节点
  • 五、环形链表的约瑟夫问题
  • 六、分割链表

一、移除链表元素

原题链接:移除链表元素

在这里插入图片描述

在这里插入图片描述

一个解法是遍历原链表,将与val相等的结点抛弃,链接后一个结点

在这里插入图片描述

另一个解法是创建一个新的链表,不保存与val相等的结点

在这里插入图片描述

注意:新的链表如果还没有插入结点,首先应该先将目的结点成为首结点
并且最后的尾结点的next应该置空

struct ListNode* removeElements(struct ListNode* head, int val)
{struct ListNode* cur =  head;struct ListNode* phead = NULL;struct ListNode* ptail = NULL;while(cur){if(cur->val != val){//设置头结点if(phead == NULL){phead = ptail = cur;}else{//尾插ptail->next = cur;ptail = ptail->next;}}cur = cur->next;}if(ptail){ptail->next = NULL;}return phead;
}

二、反转链表

原题链接:反转链表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一种解法是创建一个新的链表,遍历原链表,倒着储存进新的链表

另一个解法比较巧妙,需要三个指针
在这里插入图片描述

struct ListNode* reverseList(struct ListNode* head)
{if(head == NULL){return head;}struct ListNode* n1 = NULL;struct ListNode* n2 = head;struct ListNode* n3 = head->next;while(n2){n2->next = n1;n1 = n2;n2 = n3;if(n3){n3 = n3->next;}}return n1;
}

三、合并两个有序链表

原题链接:合并两个有序链表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
思路:创建一个新的链表,将上面两个链表遍历,将小的结点先储存在新的链表中
最后要么list1先遍历完,要么list2先遍历完,在写一个判断,将没有遍历完的链表的结点直接尾插到新的链表的末尾

注意:我们可以先创建一个哨兵位,方便我们直接插入数据,不在判断新的链表是否为空
在这里插入图片描述

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{if(list1 == NULL){return list2;}if(list2 == NULL){return list1;}//创建哨兵位struct ListNode* phead = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* ptail = phead;struct ListNode* pcur1 = list1;struct ListNode* pcur2 = list2;while(pcur1 && pcur2){if(pcur1->val < pcur2->val){ptail->next = pcur1;ptail = ptail->next;pcur1 = pcur1->next;}else{ptail->next = pcur2;ptail = ptail->next;pcur2 = pcur2->next;}}if(pcur1){ptail->next = pcur1;}if(pcur2){ptail->next = pcur2;}struct ListNode* ret = phead->next;free(phead);phead = NULL;return ret;
}

四、链表的中间节点

原题链接:链表的中间节点

在这里插入图片描述
在这里插入图片描述

使用快慢指针可以很好的解决这个问题
在这里插入图片描述

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

五、环形链表的约瑟夫问题

原题链接:环形链表的约瑟夫问题
在这里插入图片描述
在这里插入图片描述
这个问题起源于一个故事:

著名的Josephus问题 据说著名犹太历史学家 Josephus有过以下的故事:在罗⻢⼈占领乔塔帕特后,39个犹太⼈与
Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被⼈抓到,于是决定了⼀个⾃杀
⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀ 个重新报数,直到所有⼈都⾃杀⾝亡为⽌。
历史学家 然⽽Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在
第16个与第31个位置,于是逃过了这场死亡游戏。

解决这道题,可以创建一个环形链表(循环链表),将题目的数据储存在链表的结点里面

在这里插入图片描述
然后创建两个指针,一个指向头结点,一个指向尾结点

在这里插入图片描述
如果满足条件,遇到要删除的结点,先将prev->next指向pcur->next,然后释放pcur结点,再将pcur结点往后移动一次

在这里插入图片描述
如果不满足条件,移动pcur和prev一次即可

注意:最后的循环结束条件是pcur->next = pcur,即只剩下一个结点,而不是pcur->next = prev,因为它们两个可能在移动中重合

在这里插入图片描述

//创建结点
struct ListNode* BuyNode(int x)
{struct ListNode* newnode = (struct ListNode*)malloc(sizeof(struct ListNode));if(newnode == NULL){exit(1);}newnode->val = x;newnode->next = NULL;return newnode;
}
//创建环形链表
struct ListNode* CreatCirle(int n)
{struct ListNode* phead = BuyNode(1);struct ListNode* ptail = phead;for(int i = 2;i <= n;i++){ptail->next = BuyNode(i);ptail = ptail->next;}//将尾结点和头结点连接起来ptail->next = phead;return ptail;
}
int ysf(int n, int m )
{int count = 1;struct ListNode* prev = CreatCirle(n);struct ListNode* pcur = prev->next;while(pcur->next != pcur){if(count == m){prev->next = pcur->next;free(pcur);pcur = prev->next;count = 1;}else{prev = pcur;pcur = pcur->next;count++;}}return pcur->val;
}

六、分割链表

原题链接:分割链表

在这里插入图片描述
在这里插入图片描述

解法一:创建两个新的链表,小的放在一起,大的放在一起,最后将小的链表后面合并上大的链表
解法二:在原链表的基础上,遍历链表,将小的位置不变,将大的尾插到链表的最后,删除前面的大的结点
解法三:创建一个新的链表,将小的结点头插,大的结点尾插

下面我们围绕解法一来解决这道题

在这里插入图片描述

为方便在新的链表里面插入结点,我们可以创建哨兵位,最后释放哨兵位就行了
注意:在合并后的链表里面,最后的结点的next一定要置为空并且它的位置在合并链表之前,因为大的链表如果没有结点,则只有一个哨兵位,没有next的指向,交换位置后会使用next指针导致出现错误

struct ListNode* partition(struct ListNode* head, int x)
{//空链表if(head == NULL){return head;}//创建小的链表struct ListNode* lessnode = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* lesstail = lessnode;//创建大的链表struct ListNode* greaternode = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* greatertail = greaternode;//遍历链表struct ListNode* pcur = head;while(pcur){if(pcur->val < x){lesstail->next = pcur;lesstail = lesstail->next;}else{greatertail->next = pcur;greatertail = greatertail->next;}pcur = pcur->next;}//将新的链表最后一个置为空greatertail->next = NULL;//合并链表lesstail->next = greaternode->next;struct ListNode* phead = lessnode->next;//释放哨兵位free(lessnode);lessnode = NULL;free(greaternode);greaternode = NULL;return phead;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2010-2022年上市公司彭博ESG披露评分、分项得分数据

2010-2022年上市公司彭博ESG披露评分、分项得分数据 1、时间&#xff1a;2010-2022年 2、来源&#xff1a;Bloomberg ESG 指数 3、指标&#xff1a;股票代码、股票简称、年份、ESG披露评分、环境披露评分、社会信息披露评分、治理披露评分 4、范围&#xff1a;上市公司 5、…

详解xml-java语言

1.XML在线学习手册 XML 教程 2.XML可以做什么 1.给两个程序之间进行数据通信。现在用的最多的是JSON。 2.给服务器做配置文件。 3.存储复杂的数据关系。 4.还可以充当小型的数据库。 3.书写格式 <?xml version"1.0" encoding"UTF-8" ?> <…

Ansible 自动化运维工具 - 了解和模块应用

目录 一. Ansible 的相关知识 1.1 Ansible 工具的简介 1.2 Ansible的四大组件 1.3 运维自动化工具 1.4 Ansible 和其它自动化运维工具对比 1.5 Ansible 的优缺点 二. Ansible 环境安装部署 2.1 管理端安装 ansible 2.2 配置主机清单 三. ansible 命令行模块 3.1 comm…

JavaScript中Math函数与舍入

立方根 console.log(Math.sqrt(25)); //数学方式25平方根 console.log(25 ** (1 / 2)); //25的0.5次方 console.log(8 ** (1 / 3)); //8的1/3次方计算最大最小值 console.log(Math.max(1, 5, 88, 22, 132)); //返回最大值 console.log(Math.max(1, 5, 88, 22, 132)); //…

[Flutter]创建一个私有包并使用

在Flutter中创建一个自己的私有组件&#xff08;通常称为包或库&#xff09;&#xff0c;并通过Dart的包管理工具pub进行使用。 一、创建一个新的Flutter包 1.使用命令行创建 使用Flutter命令行工具来创建一个新的包&#xff1a; $ flutter create --templatepackage my_pri…

为什么很多人不推荐你用JWT?

为什么很多人不推荐你用JWT? 如果你经常看一些网上的带你做项目的教程&#xff0c;你就会发现 有很多的项目都用到了JWT。那么他到底安全吗&#xff1f;为什么那么多人不推荐你去使用。这个文章将会从全方面的带你了解JWT 以及他的优缺点。 什么是JWT? 这个是他的官网JSON…

React + 项目(从基础到实战) -- 第11期

目标 问卷编辑器的开发 设计UI - 拆分布局 水平垂直居中 画布 y方向滚动 自定义问卷组件 后端 返回组件数据 //获取单个问卷信息{url: /api/question/:id,method: get,response: () > {return {errno: 0,data: {id: Random.id(),title: Random.ctitle(),componentList:[//…

测试用例执行的结果pass_fail_block_skip

pass fail block skip 测试用例的执行结果通常包括以下几个方面&#xff1a; 1. **测试结果状态**&#xff1a;通常分为“通过”、“失败”、“阻塞”和“跳过”等状态。 - **通过**&#xff1a;测试用例执行完毕&#xff0c;预期结果与实际结果一致。 - **失败**&am…

【AI】深度学习框架的期望与现实 机器学习编译尚未兑现其早期的一些承诺……

深度学习框架的期望与现实 机器学习编译尚未兑现其早期的一些承诺…… 来自&#xff1a;Axelera AI 资深软件工程师 Matthew Barrett 原帖是linkedin帖子&#xff1a; https://linkedin.com/posts/matthew-barrett-a49929177_i-think-its-fair-to-say-that-ml-compilation-ac…

Flask应用的部署和使用,以照片分割为例。

任务是本地上传一张照片&#xff0c;在服务器端处理后&#xff0c;下载到本地。 服务器端已经封装好了相关的程序通过以下语句调用 from amg_test import main from test import test main() test() 首先要在虚拟环境中安装flask pip install Flask 文件组织架构 your_pro…

Redis-单机安装

试图从官网注册不了我也不知道什么情况。 网盘自取吧&#xff0c;链接&#xff1a;https://pan.baidu.com/s/1KERBQaH9gCT10AGt9z0_jg?pwdyjen 安装比较简单&#xff0c;照着敲就完了每一步都试过了&#xff0c;先单机安装&#xff0c;后面搭建集群。 1.将安装包放到/usr/…

Nest 快速上手 —— (三)中间件 / 异常过滤器

一、 中间件&#xff08;Middleware&#xff09; 1.特点 中间件是一个在路由处理程序之前被调用的函数。中间件函数可以访问请求和响应对象&#xff0c;以及应用程序请求-响应周期中的next()中间件函数。下一个中间件函数通常由一个名为next的变量表示。 中间件函数可以执行以…