当前位置: 首页 > news >正文

C++算法学习——链表

        本篇我们来学习C++算法思想中一个很重要的专题:链表。链表不仅仅是算法竞赛中常见的算法,而且在企业笔试面试中也是不可或缺的一环。

        相关题解代码已经上传至作者的个人gitee中:楼田莉子/C++算法学习,喜欢请支持一下谢谢

目录

前言

        链表的基本概念

        链表的典型应用

        企业面试中的常见链表问题

链表常用的操作和技巧总结

        常用技巧

        常见操作

1、两数相加

2、两两交换链表中的节点

        算法一:递归回溯算法

        算法二:循环迭代(模拟)

3、重排链表

4、合并k个升序链表

        算法一:堆

        算法二:分治——递归

5、k个一组翻转链表


前言

        链表的基本概念

        链表是一种线性数据结构,与数组不同,它通过指针将一组零散的内存块串联起来使用。每个内存块称为一个"节点"(Node),每个节点包含两部分:

  1. 数据域:存储实际的数据
  2. 指针域:存储指向下一个节点的地址

        链表的典型应用

  1. 操作系统:文件系统的目录结构、内存管理
  2. 数据库系统:实现索引结构
  3. 浏览器:网页的前进后退功能
  4. 游戏开发:场景中的对象管理
  5. 编译器设计:符号表的管理

        企业面试中的常见链表问题

        根据面试经验,高频链表问题包括但不限于:

  1. 链表反转(单链表、部分反转)
  2. 链表环检测及环入口查找
  3. 合并两个有序链表
  4. 删除倒数第N个节点
  5. 链表排序(要求O(nlogn)时间复杂度)
  6. 复杂链表的复制(带随机指针的链表)
  7. 链表相交问题

链表常用的操作和技巧总结

        常用技巧

        1、画图(重点!!!)

        2、引入虚拟头节点

        3、大胆去定义变量

        4、快慢双指针

        常见操作

        1、创建新节点

        2、尾插

        3、头插

1、两数相加

        

        算法原理:模拟两数相加的过程

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode*cur1=l1,*cur2=l2;ListNode*newhead=new ListNode(0);//记录最终结果ListNode*prev=newhead;//尾指针int t=0;//记录进位while(cur1||cur2||t){//加第一个链表if(cur1) {t+=cur1->val;cur1=cur1->next;}if(cur2){t+=cur2->val;cur2=cur2->next;}prev->next=new ListNode(t%10);prev=prev->next;t/=10;}prev=newhead->next;delete newhead;return prev;}
};

2、两两交换链表中的节点

        算法原理:

        算法一:递归回溯算法

        这里简单介绍一下

  •         步骤

    1. 递归终止条件:如果链表为空或只有一个节点,无法交换,直接返回。

    2. 递归调用:处理当前两个节点后的剩余链表(即从第三个节点开始递归)。

    3. 回溯交换:在回溯过程中,交换前两个节点,并将交换后的节点与递归处理的结果连接。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* swapPairs(ListNode* head) {// 递归终止条件:如果当前节点为空或下一个节点为空,直接返回if (head == nullptr || head->next == nullptr) {return head;}// 递归调用:处理剩余链表(从第三个节点开始)ListNode* rest = swapPairs(head->next->next);// 回溯交换:交换前两个节点ListNode* second = head->next; // 记录第二个节点second->next = head;           // 第二个节点指向第一个节点head->next = rest;             // 第一个节点指向递归处理后的链表// 返回新的头节点(原第二个节点)return second;}
};

        算法二:循环迭代(模拟)

        

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* swapPairs(ListNode* head) {if(head==nullptr||head->next==nullptr) return head;//避免空指针解引用ListNode* newhead=new ListNode(0);newhead->next=head;ListNode*prev=newhead,*cur=prev->next,*next=cur->next,*nnext=next->next;       while(cur&&next){//交换结点prev->next=next;next->next=cur;cur->next=nnext;//修改指针prev=cur;cur=nnext;if(cur) next=cur->next;if(next) nnext=next->next;}cur=newhead->next;delete newhead;return cur;}
};

3、重排链表

        算法思想:

        1、找到链表中间节点(快慢双指针·)

        2、后半部分逆序(三指针或者头插)

        3、合并链表(双指针)

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:void reorderList(ListNode* head) {if(head==nullptr||head->next==nullptr||head->next->next==nullptr) return ;//找到链表中间节点(一定要画图考虑slow的落点)ListNode*fast=head,*slow=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;}//slow后面部分逆序——头插法ListNode*head2=new ListNode(0);ListNode*cur=slow->next;slow->next=nullptr;//把链表断开while(cur){ListNode*next=cur->next;cur->next=head2->next;head2->next=cur;cur=next;}//合并两个链表——双指针ListNode*ret=new ListNode(0);ListNode*prev=ret;ListNode*cur1=head,*cur2=head2->next;while(cur1){//先放第一个链表prev->next=cur1;cur1=cur1->next;prev=prev->next;//放第二个链表if(cur2){prev->next=cur2;cur2=cur2->next;prev=prev->next;}}delete head2;delete ret;}
};

4、合并k个升序链表

        算法思想:

        算法一:堆

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public://算法一(推荐)struct cmp{bool operator()(const ListNode*list1,const ListNode*list2){return list1->val > list2->val;}};ListNode* mergeKLists(vector<ListNode*>& lists) {//创建小根堆priority_queue<ListNode*,vector<ListNode*>,cmp>heap;    //所有结点进入小根堆for(auto& x:lists)if(x) heap.push(x);//合并k个有序链表ListNode*ret=new ListNode(0);ListNode*prev=ret;while(!heap.empty()){ListNode* t=heap.top();heap.pop();prev->next=t;prev=t;if(t->next) heap.push(t->next);}prev=ret->next;delete ret;return prev;}
};

        算法二:分治——递归

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public://算法二:(递归)ListNode* merge(vector<ListNode*>&lists,int left,int right){if(left>right) return nullptr;if(left==right) return lists[left];//平分数组int mid=left+(right-left)/2;//[left,mid][mid+1,right]//递归处理做有区间ListNode* l1= merge(lists,left,mid);ListNode* l2= merge(lists,mid+1,right);//合并两个有序链表return mergeTwolist(l1,l2);}ListNode* mergeTwolist(ListNode*l1,ListNode*l2){if(l1==nullptr) return l2;if(l2==nullptr) return l1;//合并两个链表ListNode head;ListNode*cur1=l1,*cur2=l2,*prev=&head;head.next=nullptr;while(cur1&&cur2){if(cur1->val<=cur2->val){prev=prev->next=cur1;cur1=cur1->next;}else{prev=prev->next=cur2;cur2=cur2->next;}}if(cur1) prev->next=cur1;if(cur2) prev->next=cur2;return head.next;}ListNode* mergeKLists(vector<ListNode*>& lists) {return merge(lists,0,lists.size()-1);}
};

        

5、k个一组翻转链表

        算法思想:模拟

        1、先求出逆序多少组

        2、重复n次长度为k的链表的逆序

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* reverseKGroup(ListNode* head, int k) {//先求逆序次数int n=0;ListNode*cur=head;while(cur){cur=cur->next;n++;}   n/=k;//重复n次长度为k的链表逆序ListNode*newhead=new ListNode(0);ListNode*prev=newhead;cur=head;for(int i=0;i<n;i++){ListNode*tmp=cur;for(int j=0;j<k;j++){ListNode*next=cur->next;cur->next=prev->next;prev->next=cur;cur=next;}prev=tmp;}//不需要翻转的接上prev->next=cur;cur=newhead->next;delete newhead;return cur;}
};

        本期内容就到这里结束了,喜欢请点个赞谢谢。


文章转载自:

http://oBqmAHsR.xhsxj.cn
http://tOuYoOIY.xhsxj.cn
http://KpydG2d1.xhsxj.cn
http://6IigqXKZ.xhsxj.cn
http://8WI0v4j1.xhsxj.cn
http://NsgecuLw.xhsxj.cn
http://uyyWabbC.xhsxj.cn
http://nvSetLxO.xhsxj.cn
http://N7dUgStv.xhsxj.cn
http://I9KMoKWj.xhsxj.cn
http://x7jVc4DV.xhsxj.cn
http://1vNVkrID.xhsxj.cn
http://wH7ByHHO.xhsxj.cn
http://TYNV1WNG.xhsxj.cn
http://1BcIEO7u.xhsxj.cn
http://jTmsbTUa.xhsxj.cn
http://mvP5oM4F.xhsxj.cn
http://aQ9Ree7i.xhsxj.cn
http://WiIvvJzX.xhsxj.cn
http://RZ1FjUVH.xhsxj.cn
http://ElfZTxBR.xhsxj.cn
http://jv5lxSfC.xhsxj.cn
http://cg4A6DJe.xhsxj.cn
http://wADNvd7v.xhsxj.cn
http://MLfqD5Rf.xhsxj.cn
http://GGR3JL58.xhsxj.cn
http://NavP2Ow0.xhsxj.cn
http://2XLtpdEB.xhsxj.cn
http://wwAOwU51.xhsxj.cn
http://BWkeq5uu.xhsxj.cn
http://www.dtcms.com/a/370752.html

相关文章:

  • 驱动——Platform
  • LeetCode 139. 单词拆分 - 动态规划解法详解
  • 开源AI智能名片链动2+1模式S2B2C商城小程序服务提升复购率和转介绍率的研究
  • HTTP协议——Cookie的相关概念和使用
  • redis的数据类型:Hash
  • PiscCode使用 Mediapipe 实时人脸表情识别与可视化
  • EG2104 SOP-8 带SD功能 内置600V功率MOS管 栅极驱动芯片
  • 【审核问题——托管式首次进入APP展示隐私政策弹窗】
  • MySQL+Canal同步ES延时问题全链路解决方案
  • 【高等数学】第十一章 曲线积分与曲面积分——第三节 格林公式及其应用
  • Android Kotlin 动态注册 Broadcast 的完整封装方案
  • OceanBase容量统计:租户、数据库、表大小
  • SpringAMQP
  • 软件设计师备考-(十四)数据库设计
  • Fast DDS原生程序ROS2 Rviz Debug工具接入--Overview
  • 深入理解 Next.js 的路由机制
  • 鸿蒙 BLE 蓝牙智能设备固件升级之DFU升级方式(Nordic芯片)
  • 5-10数组元素添加和删除(数组基础操作)
  • echarts实现两条折线区域中间有线连接,custom + renderItem(初级版)
  • 机器人控制器开发(传感器层——奥比大白相机适配)
  • 深入解析 JavaScript 中的 call、apply、bind:用法、差异与面试题
  • LangChain实战(十八):构建ReAct模式的网页内容摘要与分析Agent
  • OpenRouter:一站式 AI 模型调用平台,免费畅享千问、DeepSeek 等顶级模型
  • Python基础(①⑧Queue)
  • 小型磨床设计cad+三维图+设计说明书
  • EMS 抗扰度在边缘计算产品电路设计的基本问题
  • 拯救珍贵回忆:AI照片修复让老照片重获新生
  • 一款免费易用且打造的全功能媒体播放器
  • 记一次uniapp微信小程序开发scss变量失效的问题
  • 如何在Kali Linux官网下载历史版本