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

news/2025/2/12 18:13:56/

目录

 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.ppmy.cn/news/1368992.html

相关文章

MyBatis-Plus 快速入门

介绍 j​​​​​MyBatis-Plus (opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 官网&#xff1a;MyBatis-Plus (baomidou.com) 1.…

【数据分享】2001~2023年中国区域MOD17A3HGF GPP数据

各位同学们好&#xff0c;今天和大伙儿分享的是2001~2023年中国区域MOD17A3HGF GPP数据。如果大家有下载处理数据等方面的问题&#xff0c;您可以私信或评论。 Running, S., M. Zhao. <i>MODIS/Terra Net Primary Production Gap-Filled Yearly L4 Global 500m SIN Grid…

PowerData 2024“数字经济-城市开源行”活动预告

2023&#xff0c;社区经过一年的发展&#xff0c;凝聚起了一批热爱社区、热爱开源的小伙伴。 2024&#xff0c;社区计划在全国十个城市举办"数字经济-城市开源行"活动&#xff0c;连接社区成员、传播数字技术、推广开源文化&#xff0c;吸引更多伙伴加入社区&#xf…

机器学习:集成学习(Python)

一、Adaboost算法 1.1 Adaboost分类算法 adaboost_discrete_c.py import numpy as np import copy from ch4.decision_tree_C import DecisionTreeClassifierclass AdaBoostClassifier:"""adaboost分类算法&#xff1a;既可以做二分类、也可以做多分类&#…

计算机视觉基础知识(十六)--图像识别

图像识别 信息时代的一门重要技术;目的是让计算机代替人类处理大量的物理信息;随着计算机技术的发展,人类对图像识别技术的认识越来越深刻;图像识别技术利用计算机对图像进行处理\分析\理解,识别不同模式的目标和对象;过程分为信息的获取\预处理\特征抽取和选择\分类器设计\分…

『NLP学习笔记』图解GPT3(How GPT3 Works-Visualizations and Animations)

图解GPT3(How GPT3 Works-Visualizations and Animations) 文章目录 一. GPT-1 vs GPT-2 vs GPT-3 vs GPT-3.5 vs GPT-4二. GPT32.1. 训练动图2.2. 预测动图2.3. 代码生成示例三. 参考文章原作者主页:Jay Alammar原英文链接:How GPT3 Works - Visualizations and Animations …

Tomcat负载均衡、动静分离

目录 引言 实验图解 1.实验环境搭建 2.部署Nginx服务器及配置静态页面Web服务 3.部署Tomcat服务及配置动态页面Web服务 4.实验验收 动态页面 静态页面 引言 tomcat服务既可以处理动态页面&#xff0c;也可以处理静态页面&#xff1b;但其处理静态页面的速度远远不如…

一起玩儿平衡车(ESP32)——03 一边接线一边测试

摘要&#xff1a;本文介绍平衡车的接线与测试 在上一篇已经介绍了各个组件的固定位置以及接线方法&#xff0c;本文将对接线过程做一个详细的介绍&#xff0c;讲解其中的要点以及注意事项&#xff0c;确保整个接线工作可以顺利完成。 如果你是有经验的老手&#xff0c;可以保证…