数据结构·单链表经典例题

1. 移除链表元素

        OJ链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

        本题是说给出一个链表的头节点head和一个整数val,如果发现节点中存的数据有val就删掉它,最后返回修改后的链表头节点地址

        如果题目中没有明确提及给出的链表是否是带头的,那就默认是不带头的链表,此时题目中再提到头节点就是指链表的第一个节点

思路1:

        从第二个节点开始,判断其内含的数据是否是val,然后遍历链表,最后判断头节点中数据是否是val,如果是,再挪移头节点的指向

        至于为什么从第二个节点开始扫描是为了不用每次都判断一下头节点要不要移动,先把后面的节点都处理好,最后再确定头节点的指向

        但是这个思路还是太复杂了

思路2:

        创建一个新链表,把不是val的节点都丢到新链表中去,最后返回新链表的头节点

        与其说是创建了一个新链表,不如说是将原链表的链接顺序拿到一个新的地方进行更改

struct ListNode* removeElements(struct ListNode* head, int val) 
{//记录新链表的头和尾struct ListNode* newhead = NULL;struct ListNode* newtail = NULL;//pcur用来扫描原链表struct ListNode* pcur = head;while (pcur){//不是val尾插到新链表的尾if (pcur->val != val){//如果新链表为空,那么新加入的节点既是头节点也是尾节点if (newhead == NULL){newhead = pcur;newtail = pcur;}//如果链表不为空,就将新节点放到链表尾,else{newtail->next = pcur;newtail = pcur;}}//pcur指向的节点是不是val都要往下走pcur = pcur->next;}//因为有可能返回的是空链表,所以不能粗暴的去访问newtail->next//要先判断要返回的newtail是否为空,也就是说是否是空链表if (newtail){newtail->next = NULL;}return newhead;
}

2. 链表的中间结点

        OJ链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

        本题是说,给出一个链表的头节点head,然后找到这个链表的中间节点,如果有两个中间节点,就返回第二个中间节点

思路1:

        遍历整个链表,数出一共有几个节点,然后通过除2找到中间节点的"下标",然后通过"下标",再访问出中间节点的地址

        很明显,这个方法很麻烦

思路2:快慢指针法

        跟前面双指针那节一样,这个快慢指针也不是真正的创造两个指针,而是创造两个具有类似指针功能的变量

        思路就是创造一个慢指针slow,一个快指针fast,然后slow走一步,fast走两步,这样fast走完的时候slow刚好来到链表中间

        快慢指针法就是通过只遍历一次就能达到对整体进行类似除法运算的功效,比如slow走1步fast走4步,fast走完,slow就走到整体的四分之一处

        回到本题,在判断结束扫描的条件时要注意,先判断fast是否为NULL,利用短路的特性避免判断fast->next,因为如果fast为假了,去访问next的时候就会崩

struct ListNode* middleNode(struct ListNode* head) 
{struct ListNode* slow = head;struct ListNode* fast = head;//有一个为假就跳出循环while (fast && fast->next){slow = slow->next;fast = fast->next->next;}return slow;
}

3. 反转链表

        OJ链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

        本体是说给一个单链表的头节点地址head,让反转链表,再将新链表的头返回,值得注意的是这个链表可能是个空链表

思路1:

        和第一题类似,创建一个"新链表",每次将旧链表的第一个节点拿下来,头插到新链表

        因为这题给的是单链表,不能用后面的节点访问前面的节点,所以不要想从最后一个节点开始改变链接方向,因为遍历到最后一个节点就找不到前面的节点了

思路2:

        用3个指针n1、n2、n3,初始状态n1指向空,n2指向头节点,n3指向第二个节点。然后将n2节点的指向变成n1,然后把n1变到n2的位置,n2变到n3的位置,再把n3滑到下一个节点。然后在n2不为空的情况下一直循环这个操作。

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;n3 = n2;//如果n3已经指向NULL了就不用往下滑了if (n3){n3 = n3->next;}        }return n1;
}

4. 合并两个有序链表

        OJ链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

        本题是说,给两个升序链表的头节点地址list1和list2,然后将两个链表合并成一共新的升序链表,并返回新链表的头,值得注意的是给出的两个链表可能有空的

思路:

        创建一个"新链表",再用顺序表中讲到的那道合并数组的题的思想

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{//如果给出的某个链表为空,就返回另一个链表if (list1 == NULL){return list2;}if (list2 == NULL){return list1;}//两个扫描原链表的指针struct ListNode* p1 = list1;struct ListNode* p2 = list2;//两个控制新链表的指针struct ListNode* newhead = NULL;struct ListNode* newtail = NULL;//p1或p2有一个扫描完就退出循环while (p1 && p2){//如果p1扫到的数据更小if (p1->val < p2->val){//如果新链表中没有节点if (newhead == NULL){newhead = p1;newtail = p1;}//如果新链表不为空else{newtail->next = p1;newtail = p1;}p1 = p1->next;}//如果p2扫到的数据更小else{//如果新链表为空if (newhead == NULL){newhead = p2;newtail = p2;}//如果新链表不为空else{newtail->next = p2;newtail = p2;}p2 = p2->next;}}//处理旧链表没挪完的那部分if (p1){newtail->next = p1;}if (p2){newtail->next = p2;}return newhead;
}

5. 分割链表(带头链表的优势)

        本题我会距离说明带头链表比不带头链表好在哪里

        OJ链接:https://leetcode.cn/problems/partition-list-lcci/description/

        本题给出一个链表的头节点地址,和一个特定的值x,要求是把所存数据小于x的节点堆在前面,把大于等于x的节点堆在后面,堆放的时候不需要保存节点原来相对位置的有关信息

思路1:

        创建一个"新链表"把原链表中小于x的节点头插,把大于等于x的节点尾插

思路2:带头链表的优点

        先说解题思路,我们创造两个"新链表",lesshead尾插小于x的节点,bighead尾插大于等于x的节点,最后把bighead连到lesshead后面

        现在我们回忆一下,之前的代码再每次插入新节点的时候都要判断一下链表是否为空,这很麻烦。所以我们直接让链表带头,这样每次插入新节点的时候就不用判断了,因为链表一定不为空,它有一个不存储数据的头或者说"哨兵位",省去了插入时的很多麻烦

struct ListNode* partition(struct ListNode* head, int x) 
{//判断传过来的是否时空链表if (head == NULL){return head;}//创建两个带头新链表struct ListNode* lesshead, * lesstail;struct ListNode* bighead, * bigtail;//申请头节点空间,并将其地址记录lesshead = lesstail = (struct ListNode*)malloc(sizeof(struct ListNode));bighead = bigtail = (struct ListNode*)malloc(sizeof(struct ListNode));//用pcur遍历原链表,将节点放到对应的新链表中struct ListNode* pcur = head;while (pcur){if (pcur->val < x){lesstail->next = pcur;lesstail = lesstail->next;}else{bigtail->next = pcur;bigtail = bigtail->next;}pcur = pcur->next;}//链接两个链表//先将大链表的尾置空bigtail->next = NULL;//再接上,注意要掠过大链表的那个没意义的头lesstail->next = bighead->next;//先存上小链表的第一个存有效数据的节点struct ListNode* ret = lesshead->next;//在释放两个新链表的头free(bighead);free(lesshead);return ret;
}

6. 环形链表的约瑟夫问题

        OJ链接:环形链表的约瑟夫问题_牛客题霸_牛客网

        本题······哎呀这题我就不复述了,人家题干说的挺清楚的

思路:循环链表

        创建不带头单向循环链表,模拟围成一圈的人,逢m就删除节点

#include<stdlib.h>
//创建新节点
struct ListNode* BuyNode(int x)
{struct ListNode* newnode = (struct ListNode*)malloc(sizeof(struct ListNode));newnode->val = x;newnode->next = NULL;return newnode;
}
//创建链表
struct ListNode* creatlist(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 phead;
}int ysf(int n, int m) 
{//创建不带头单向循环链表struct ListNode* phead = creatlist(n);struct ListNode* pcur = phead;struct ListNode* prev = NULL;//逢m删除节点,直到剩下最后一个节点int count = 1;while (pcur->next != pcur){if (m == count){//删除当前节点prev->next = pcur->next;free(pcur);count = 1;pcur = prev->next;}else{//pcur往后走prev = pcur;pcur = pcur->next;count++;}}return pcur->val;
}

        不必担心当 m==1 的使得 prev->next 非法的情况,while的循环条件就已经把这种情况挡在外面了,而且题干里说了一定会剩下来一个人,所以返回pcur的数据也是没有问题的。

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

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

相关文章

第十八讲_HarmonyOS应用开发实战(实现电商首页)

HarmonyOS应用开发实战&#xff08;实现电商首页&#xff09; 1. 项目涉及知识点罗列2. 项目目录结构介绍3. 最终的效果图4. 部分源码展示 1. 项目涉及知识点罗列 掌握HUAWEI DevEco Studio开发工具掌握创建HarmonyOS应用工程掌握ArkUI自定义组件掌握Entry、Component、Builde…

【Redis】关于它为什么快?使用场景?以及使用方式?为何引入多线程?

目录 1.既然redis那么快&#xff0c;为什么不用它做主数据库&#xff0c;只用它做缓存&#xff1f; 2.Redis 一般在什么场合下使用&#xff1f; 3.redis为什么这么快&#xff1f; 4.Redis为什么要引入了多线程&#xff1f; 1.既然redis那么快&#xff0c;为什么不用它做主数据…

Nginx 配置解析:从基础到高级应用指南

Nginx 配置解析&#xff1a;从基础到高级应用指南 Nginx 配置解析&#xff1a;从基础到高级应用指南1. 安装和基本配置安装 Nginx基本配置 2. 虚拟主机配置3. 反向代理配置4. 负载均衡配置5. SSL 配置6. 高级配置选项结语 Nginx 配置解析&#xff1a;从基础到高级应用指南 Ngi…

C#使用OpenCvSharp4库读取电脑摄像头数据并实时显示

一、OpenCvSharp4库 OpenCvSharp4库是一个基于.Net封装的OpenCV库&#xff0c;Github源代码地址为&#xff1a;https://github.com/shimat/opencvsharp&#xff0c;里面有关于Windows下安装OpenCvSharp4库的描述&#xff0c;如下图所示&#xff1a; 二、C#使用OpenCvSharp4库…

Python tkinter (8) ——Spinbox控件

Python的标准Tk GUI工具包的接口 tkinter系列文章 python tkinter窗口简单实现 Python tkinter (1) —— Label标签 Python tkinter (2) —— Button标签 Python tkinter (3) —— Entry标签 Python tkinter (4) —— Text控件 Python tkinter (5) 选项按钮与复选框 Pyt…

中间件安全

中间件安全 vulhub漏洞复现&#xff1a;https://vulhub.org/操作教程&#xff1a;https://www.freebuf.com/sectool/226207.html 一、Apache Apache(音译为阿帕奇)是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上&#xff0c;由于其跨平台和…

RT-DETR改进有效系列目录 | 包含卷积、主干、RepC3、注意力机制、Neck上百种创新机制

💡 RT-DETR改进有效系列目录 💡 前言 Hello,各位读者们好 Hello,各位读者,距离第一天发RT-DETR的博客已经过去了接近两个月,这段时间里我深入的研究了一下RT-DETR在ultralytics仓库的使用,旨在为大家解决为什么用v8的仓库训练的时候模型不收敛,精度差的离谱的问题,…

智能小程序页面配置、运行机制及路由

页面介绍 Page 代表应用的一个页面&#xff0c;负责页面展示和交互。每个页面对应一个子目录&#xff0c;一般有多少个页面&#xff0c;就有多少个子目录。它也是一个构造函数&#xff0c;用来指定页面的初始数据、生命周期回调、事件处理函数等。 每个小程序页面一般包含以下…

MarkDown快速入门-以Obsidian编辑器为例

直接上图&#xff0c;左右对应。 首先是基础语法。 # 标题&#xff0c;几个就代表几级标题&#xff1b;* 单个是序号&#xff0c;两个在一起就是斜体&#xff1b;- [ ] 代表任务&#xff0c;注意其中的空格&#xff1b; 然后是表格按钮代码 | 使用中竖线代表表格&#xff0c…

Ubuntu22.04安装docker

君衍. 一、认识docker二、查看Docker的依赖三、在Ubuntu22.04上安装Docker步骤1、更新Ubuntu2、添加Docker库3、安装Docker4、Docker测试 四、安装docker-compose 一、认识docker Docker是一个软件容器平台&#xff0c;属于Linux容器的一种封装&#xff0c;同时提供简单易用的…

3. 构建以太网交换网络

3.1 实验一&#xff1a;以太网基础与 VLAN 配置实验 3.1.1 实验介绍 3.1.1.1 关于本实验 以太网是一种基于 CSMA/CD&#xff08;Carrier Sense Multiple Access/Collision Detection&#xff09;的共享通讯介质的数据网络通讯技术。当主机数目较多时会导致冲突严重、广播泛滥…

python222网站实战(SpringBoot+SpringSecurity+MybatisPlus+thymeleaf+layui)-友情链接管理实现

锋哥原创的SpringbootLayui python222网站实战&#xff1a; python222网站实战课程视频教程&#xff08;SpringBootPython爬虫实战&#xff09; ( 火爆连载更新中... )_哔哩哔哩_bilibilipython222网站实战课程视频教程&#xff08;SpringBootPython爬虫实战&#xff09; ( 火…

github连不上

github连不上 错误提示解决方案steam 采用Hosts加速 错误提示 fatal: unable to access ‘https://github.com/Ada-design/qianduan.git/’: Failed to connect to github.com port 443 after 21073 ms: Couldn’t connect to server 解决方案 下载steam https://steampp.ne…

latent-diffusion model环境配置--我转载的

latent-diffusion model环境配置&#xff0c;这可能是你能够找到的最细的博客了_latent diffusion model 训练 autoencoder-CSDN博客 前言 最近在研究diffusion模型&#xff0c;并对目前最火的stable-diffusion模型很感兴趣&#xff0c;又因为stable-diffusion是一种latent-di…

Mysql大数据量分页优化

前言 之前有看过到mysql大数据量分页情况下性能会很差&#xff0c;但是没有探究过它的原因&#xff0c;今天讲一讲mysql大数据量下偏移量很大&#xff0c;性能很差的问题&#xff0c;并附上解决方式。 原因 将原因前我们先做一个试验&#xff0c;我做试验使用的是mysql5.7.2…

Arm AArch64 alignment(对齐)

数据和指令必须与合适的边界保持对齐(alignment)。访问是否对齐会影响ARM核的性能&#xff0c;并且在将代码从早期的体系结构移植到ARMv8-A时可能会出现可移植性问题。出于性能原因&#xff0c;或者在移植代码时&#xff0c;都值得去注意下对齐问题。本文将讲述了ARMv8-A AArch…

初识人工智能,一文读懂贝叶斯优化进阶的知识文集(9)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

[机器学习]简单线性回归——梯度下降法

一.梯度下降法概念 2.代码实现 # 0. 引入依赖 import numpy as np import matplotlib.pyplot as plt# 1. 导入数据&#xff08;data.csv&#xff09; points np.genfromtxt(data.csv, delimiter,) points[0,0]# 提取points中的两列数据&#xff0c;分别作为x&#xff0c;y …

[BUUCTF]-PWN:pwnable_hacknote解析

先看保护 32位&#xff0c;没开pie&#xff0c;got表可修改 看ida 总的来说就是alloc创建堆块&#xff0c;free释放堆块&#xff0c;show打印堆块内容 但alloc处的函数比较特别&#xff0c;他会先申请一个0x8大小的堆来存放与puts相关的指针 完整exp&#xff1a; from pwn …