【数据结构和算法初阶(C语言)】顺序表+单链表经典例题图文详解(题解大合集,搭配图文演示详解,一次吃饱吃好)

目录

 1.移除链表元素

1.1思路1:遍历删除 

1. 2  思路2:尾插法 

2.反转链表 

3.链表的中间节点 

 3.1解题思想及过程

3.2快慢指针思想解题---变式:返回链表的倒数第K个节点 

4.合并两个有序链表

4.1解题思想 1取小的尾插

5.反转链表

6、CM11 链表分割 (比较难)

描述

7.OR36 链表的回文结构

8.相交链表 

9.结语


 1.移除链表元素

1203. 移除链表元素icon-default.png?t=N7T8https://leetcode.cn/problems/remove-linked-list-elements/

 

1.1思路1:遍历删除 

struct ListNode* removeElements(struct ListNode* head, int val) {if(head==NULL)
{return NULL;
}struct ListNode* cur = head;
struct ListNode* pre = head;while(cur->next)
{if(cur->val==val){//删除//如果是头结点if(head == cur){head = cur->next;free(cur);cur = head;pre = cur;}else{pre->next = cur->next;free(cur);cur = pre->next;}}else {pre= cur;cur = cur->next;}}
//处理尾巴
if(cur->val == val)
{if(head == cur){free(cur);return NULL;}else{pre->next = cur ->next;free(cur);}
}return head;
}

1. 2  思路2:尾插法 

struct ListNode* removeElements(struct ListNode* head, int val) {// if(head==NULL)
// {
//     return NULL;
// }
//  struct ListNode* cur = head;
// struct ListNode* pre = head;// while(cur->next)
// {
//     if(cur->val==val)
//     {
//         //删除
//         //如果是头结点
//         if(head == cur)
//         {
//             head = cur->next;
//             free(cur);
//             cur = head;
//             pre = cur;//         }
//         else
//         {
//             pre->next = cur->next;
//             free(cur);
//             cur = pre->next;//         }
//     }
//     else 
//     {
//         pre= cur;
//         cur = cur->next;
//     }// }
// //处理尾巴
// if(cur->val == val)
// {
//     if(head == cur)
//     {
//         free(cur);
//         return NULL;
//     }
//     else{
//         pre->next = cur ->next;
//         free(cur);
//     }
// }// return head;struct ListNode* cur = head;//用于遍历链表
struct ListNode* newhead = NULL;//创建新的头结点
struct ListNode* tail = NULL;//定义一个尾指针
//开始遍历原先的链表
while(cur)
{if(cur->val == val){struct ListNode* deal = cur;//记录一下要删除的节点cur = cur->next;free(deal);}else {if(tail == NULL)//第一次插入{tail = cur;newhead = cur;} else {tail ->next = cur;tail = tail ->next;}cur = cur->next;}//单独处理一下尾巴最后一个节点要删除的话,我们的这个尾节点要为空if(tail){tail->next = NULL;}}
return newhead;}

 

2.反转链表 

206. 反转链表icon-default.png?t=N7T8https://leetcode.cn/problems/reverse-linked-list/ 放在第五讲解

3.链表的中间节点 

. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/middle-of-the-linked-list/

 3.1解题思想及过程

这道题最简单的方法就是两次遍历的方法,第一次遍历就可以得到链表的长度,从而求得链表的的中间位置,第二次遍历返回中间节点就好。今天重点讲解一次遍历方法使用快慢指针

偶数长度的链表遍历结束的条件是:快指针指向空

奇数链表长度的遍历结束的条件是:快指针指向的下一个位置为空 

struct ListNode* middleNode(struct ListNode* head) {//快慢指针struct ListNode*  slow = head;struct ListNode*  fast = head;if(head == NULL)//传入空指针{return NULL;}while(fast&&fast->next){slow = slow->next;fast = fast->next->next;}return slow;}

 

3.2快慢指针思想解题---变式:返回链表的倒数第K个节点 

解题思想:快慢指针

快指针先走K步,然后和慢指针一起移动,直到快指针来到尾节点的下一个位置过后,慢指针指向的位置就是我们的倒数第k个节点。

特别注意就是:如果我们传入空链表或者我们的输入的倒数第几个的数据,但是链表没有那么长的时候,应该返回空。 

struct ListNode* FindKthToTail(struct Listnode* plistHead, int k)
{//首先判断一下链表为不为空,为空就返回NULLif (plistHead == NULL){return NULL;}struct ListNode* slow, * fast;slow = fast = plistHead;//先让快指针走K步while (k--){//但是要注意判断如果我们的链表没有K步长,就返回空if (fast == NULL){return NULL;}fast = fast->next;}//然后快慢指针一起走,直到快指针走到空while (fast){slow = slow->next;fast = fast->next;}return slow;
}

 

4.合并两个有序链表

21. 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

4.1解题思想 1取小的尾插

主要是尾插思想,由于是有序链表,我们就取小的尾差到新的头结点,当一个链表或者两个链表同时走完就结束,将另外一个链表剩下的所有元素尾插到新的链表中然后返回头结点就可以。为了不增加遍历的时间复杂度,还是定义一个尾指针。

 

当有一个链表先走完时:
 

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {struct ListNode* head = NULL;//定义一个头指针struct ListNode* tail = NULL;//定义一个尾指针//先判断传入的链表中1是否有空链表,有就返回另外一个if(list1 == NULL){return list2;}if(list2==NULL){return list1;}while(list1 && list2){if(list1->val< list2->val)//取小的尾插{if(tail == NULL)//判断是否是第一次插入{tail = head = list1;list1 = list1->next;}else{tail->next= list1;list1 = list1->next;tail = tail->next;}}else{if(tail == NULL)//判断是否是第一次插入{tail = head = list2;list2 = list2->next;}else{tail->next= list2;tail = tail->next;list2 = list2->next;}}}//出循环有一个链表为空,就要判断一下是哪一个为空,然后将另外一个进行尾插if(list1){tail->next = list1;}if(list2){tail->next = list2;}return head;
}

 

5.反转链表

. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/reverse-linked-list/ 

 

 解题思想:头插法

 

 

struct ListNode* reverseList(struct ListNode* head) {//先判断一下传入的链表是否为空
if(head == NULL)
{return NULL;
}struct ListNode*  newhead = NULL;struct ListNode* cur = head;struct ListNode*  after=NULL;while(cur){after = cur->next;cur ->next = newhead;newhead = cur;cur = after;}return newhead;
}

 

6、CM11 链表分割 (比较难)

描述

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

做题链接

补充带哨兵位的链表

 

首先解题的整体思想:
大于等于X的放置在一个链表,使用尾插的办法为了不改变顺序

小于X的放置在一个链表,也使用尾插的办法。

最后将两个链表链接起来。

这里使用带哨兵位的链表。我们先看一下代码实现,一边走一边说明问题

 

 

 

那么我们应该将大于数据的链表的尾巴置空。 

class Partition {
public:ListNode* partition(ListNode* pHead, int x) {// write code herestruct ListNode* lhead ,*ltail;//定义小于X的值存放的链表的头尾节点struct ListNode* ghead ,*gtail;//定义大于X的值存放的链表的头尾节点//申请哨兵位空间lhead = ltail = (  struct ListNode*)malloc(sizeof(  struct ListNode));ghead = gtail = (  struct ListNode*)malloc(sizeof(  struct ListNode));//开始循环遍历找struct ListNode* cur= pHead;while(cur){if(cur->val <x){ltail ->next = cur;ltail = ltail ->next;cur = cur->next;}else {gtail->next = cur;gtail = gtail->next;cur = cur->next;}}//链接ltail->next = ghead->next;gtail->next = NULL; free(ghead);struct ListNode* head = lhead;head = head ->next;free(lhead);return head;}
};

7.OR36 链表的回文结构

题目地址

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。 给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。 测试样例: 1-2-2-1 返回:true

struct ListNode* reverseList(struct ListNode* head) {//先判断一下传入的链表是否为空if (head == NULL){return NULL;}struct ListNode* newhead = NULL;struct ListNode* cur = head;struct ListNode* after = NULL;while (cur){after = cur->next;cur->next = newhead;newhead = cur;cur = after;}return newhead;
}struct ListNode* middleNode(struct ListNode* head) {//快慢指针struct ListNode* slow = head;struct ListNode* fast = head;if (head == NULL)//传入空指针{return NULL;}while (fast && fast->next){slow = slow->next;fast = fast->next->next;}return slow;}
bool chkPAlindrome(ListNode* head)
{struct ListNode* mid = middleNode(head);struct LIstNOde* rmid = reverselist(mid);while (rmid && head){struct ListNode* scur = head;if(rmid->val != scur ->val)return false;rmid = rmid->next;scur = head->next;}}

8.相交链表 

160. 相交链表

 

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++;//计算链表a的长度}while(curb->next){curb = curb->next;lenb++;//计算链表b的长度}//如果两个链表相交,那么尾结点的地址一定相等//所以这里就可以判断一下两个链表是否相交if(cura != curb){return NULL;}int gap = abs(lena-lenb);//计算两个链表之间的差值,用来绝对值struct ListNode*longst = headA,*shortlist = headB;if(lena<lenb){longst = headB;shortlist = headA;}while(gap--){longst = longst->next;//长的先走差距步}//同时找交点while(longst != shortlist){longst = longst->next;shortlist = shortlist->next;}return longst;
}

 

9.结语

今天关于简单链表的题目解析就更新到这里,下几篇内容是比较复杂的带环链表和复杂连边的题目,大家可以先收藏或者关注一波,方便链接后续新解 

 

 

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

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

相关文章

W-TinyLFU 算法实现

前言 不同于常见的 LRU 或 LFU&#xff0c;Window TinyLFU 是一种非常高效的缓存设计方案。先来看下 LRU 和 LFU 算法的缺点&#xff1a; LFU 缺点&#xff1a; 需要为每个记录项维护频率信息&#xff0c;这将消耗大量的内存空间可能存在旧数据长期不被淘汰&#xff08;一开…

运筹学_1.1.3 线性规划问题-化标准型

1.1.3 线性规划问题-化标准型 一、线性规划模型的标准型&#xff08;完全展开式&#xff09;二、线性规划问题的共同特征与建模思路三、线性规划的标准型&#xff08;三种形式&#xff09;1、完全展开式2、完全展开式向量化3、完全展开式矩阵化 四、化标准型&#xff08;完全展…

回溯 Leetcode 47 全排列II

全排列II 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 Leetcode 47 学习记录自代码随想录 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2], [1,2,1], [2,1,1]] 示例 2&#xff1a; 输入&#xff1…

【考研数学】汤家凤1800题什么水平?

作者&#xff1a;气球 链接&#xff1a;https://www.zhihu.com/question/377591845/answer/3415914549 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 汤家凤1800题是我做过的题集中比较简单好上手的了 1800题分为…

新一代电话机器人开源PHP源代码

使用easyswoole 框架开发的 新一代电话机器人开源PHP源码 项目地址&#xff1a;https://gitee.com/ddrjcode/robotphp 代理商页面演示地址 http://119.23.229.15:8080 用户名&#xff1a;c0508 密码&#xff1a;123456 包含 AI外呼管理&#xff0c;话术管理&#xff0c;CR…

PBM学习——从基础到精通!!!

本专栏着重讲解PBM学习所得,学习笔记、心得,并附有视频素材资料,视频详细目录如下: PBM相关参数解释1 PBM相关参数解释2 PBM相关案例实践1 PBM相关案例实践2 PBM相关案例实践2 PBM相关案例实践3 PBM多相流中次相界面设置1 PBM多相流中次相界面设置2 欧拉多相流曳力1 欧拉多…

住房贷款利息退税笔记

应该缴税了才能退税&#xff0c;如果是学生&#xff0c;没有缴税应该是无法退税的。 产权证明 如果是商品房&#xff0c;没有取得房产证&#xff0c;那就是房屋预售合同 扣除年度 应选择上一年 扣除比例 没有结婚&#xff0c;选否 申报方式

VUE3:省市区联级选择器

一、实现效果 二、代码展示 <template><div class"page"><select v-model"property.province"><option v-for"item in provinces" :key"item">{{ item }}</option></select><select v-model&…

lottie加载带图片的json 预览

背景 产品看到一款app的动效很不错&#xff0c;让我去模仿实现。 第一步 获取apk中的静态资源 拿到这个app的apk后&#xff0c;直接使用压缩工具解压&#xff0c; assets文件夹就是静态资源的目录 静态资源里面有lottie 那么大部分的动效应该都是lottie实现的 网上找了很多…

微信小程序,h5端自适应登陆方式

微信小程序端只显示登陆(获取opid),h5端显示通过账户密码登陆 例如: 通过下面的变量控制: const isWeixin ref(false); // #ifdef MP-WEIXIN isWeixin.value true; // #endif

【饮食】日常零食 保健食品分类(附食品营养成分表与执行标准,Coursera营养学课程笔记)

程序员生活指南之 【饮食】日常零食 & 保健食品分类和推荐&#xff08;附食品营养成分表与执行标准&#xff09; 文章目录 一、保健食品1、什么是保健食品&#xff1f;2、常见保健食品分类3、常见保健食品推荐 二、日常零食&#xff08;食品营养成分表与执行标准&#xff0…

02:Logstash|Web日志实时分析

Logstash|Web日志实时分析 logstashlogstash工作结构安装Logstash编写logstash配置文件步骤一:codec类插件插件帮助手册Logstash input插件步骤一:file模块插件filter grok插件Web日志实时分析部署beats与filebeat步骤一:filter grok模块插件logstash 一个数据采集、加工处…