数据结构算法——单链表及其操作
来源:互联网 发布:学数控编程用什么软件 编辑:程序博客网 时间:2024/06/06 01:09
单链表是一种非常常用的数据结构,虽然很简单,但是其相关操作还是很容易出错。本文将介绍单链表的几种操作,主要包括链表的反转,链表的排序,求出链表倒数第 k 个值,删除当前节点和找出链表的中间节点。
更多内容可参考如下链接:
https://www.61mon.com/index.php/archives/179/
单链表节点结构
定义单链表的节点结构如下:
/* 单链表节点结构 */struct Node{ int data; Node * next; Node() { data = 0; next = nullptr; }};/* 定义头节点 */Node * header = new Node;
链表反转
链表反转是面试笔试中非常常见的题型,需要注意的是反转过程中不能出现中断的情况。
示例:1->2->3->4->5; 反转后:5->4->3->2->1
反转过程中两个指针同步移动,具体代码如下:
/* 反转链表 */void reverse(Node * header){ if(!header->next || !header->next->next)//空链表或只有一个节点 return; Node* cur = header->next;//指向链表第一个节点 Node* pre = nullptr; while(cur) { Node* tmp = cur->next;//保存下一节点 cur->next = pre;//更改节点指向 pre = cur;//pre向前移动一步 cur = tmp;//cur向前移动一步 } header->next = pre;//头节点指向反转后的第一个节点}
链表的排序
排序采用快速排序的思想,只需要设置两个指针 i 和 j,这两个指针均往 next 方向移动,移动的过程中始终保持区间 [1, i] 的 data 都小于 base(位置 0 是主元),区间 [i+1, j) 的 data 都大于等于 base,那么当 j 走到末尾的时候便完成了一次支点的寻找。
/** * 链表升序排序 * * begin 链表的第一个结点,即 header->next * end 链表的最后一个结点的 next */void asc_sort(Node * begin, Node * end){ if(!begin || !begin->next)// 链表为空或只有一个节点 return; int base = begin->data;// 设置主元 Node* i = begin; // i 左边的小于 base Node* j = begin->next; // i 和 j 中间的大于 base while(j!=end) { if(j->data<base) { i = i->next; swap(i->data, j->data); } swap(i->data, begin->data); // 交换主元和 i 的值 } // asc_sort(begin, i); // 递归左边 asc_sort(i->next, end); // 递归右边}//使用方式asc_sort(header->next, nullptr);
求出链表倒数第 k 个值
由于链表长度未知,如果从头扫描一遍链表后得到链表长度,然后再从头找到倒数第k个数,这种方法最直观,但是时间复杂度较高。我们假设 k 小于等于链表长度,那么我们可以设置两个指针 p 和 q,这两个指针在链表里的距离就是 k,那么后面那个指针走到链表末尾的 nullptr 时,另一个指针肯定指向链表倒数第 k 个值。
/* 返回链表倒数第k个值 */int kth_last(Node * header, int k){ Node* p = header->next; Node* q = header->next; for(int i=0;i<k;i++) { if(!q) return -1; //链表长度小于k q = q->next; } while(q) { p = p->next; q = q->next; } return p->data;}
删除当前节点
要求删除节点的时间平均复杂度为O(1),这样就不能通过扫描链表获取当前节点的前一个节点的方法了。既然指针不能从当前节点的上一个节点指向当前节点的下一个节点,那么就改变当前节点的值为下一个节点的值,同时将下一个节点删除。需要注意的是删除最后一个节点的情况,因为没有下一个节点,故需要找到上一个节点,同样需要扫描链表。
/* 删除当前结点 */void del(Node * header, Node * position){ if(!position->next) // 要删除的是最后一个节点 { Node* p = header; while(p->next!=position) p = p->next; // 找到 position 的前一个结点 p->next = nullptr; delete position; } else { Node* p = position->next; swap(position->data, p->data); position->next = p->next; delete p; }}
找出链表的中间节点
通过寻找倒数第k个数的操作后,我们可以想到用类似的两个指针进行操作,这里就采用快慢指针,慢指针走的长度等于快慢指针相距的程度,所以利用这个性质,当快指针走到链表尾时,慢指针正好在中间结点。
/* 找出单链表的中间结点 */Node * find_middle(Node * header){ Node* p = header; Node* q = p; while(q->next->next && p->next) { p = p->next; // 慢指针走一步 q = q->next->next; // 快指针走两步 } return p;}
- 数据结构算法——单链表及其操作
- 数据结构——矩阵及其常用操作
- 数据结构 ——单链表操作的算法
- 数据结构与算法—常用数据结构及其Java实现
- 《C算法》——基本数据结构及其算法
- 数据结构——二叉树及其基本操作
- 数据结构与算法Java版——图及其遍历
- 数据结构——单链表(链表操作算法集合)
- 数据结构与算法——单链表的基本操作
- 数据结构 ——队列操作的算法
- 数据结构与算法复习(20)—— KMP 与字符串算法及其扩展
- 数据结构——单链表操作
- 数据结构—单链表的操作
- 常用的数据结构及其算法
- 数据结构-绪论-算法及其描述
- 数据结构算法——单链表
- 数据结构与算法—单链表
- 数据结构与算法——栈的相关操作
- io-nio-socket步步为营(五)netty框架
- ARC forbids Objective-C objects in struct
- jstl 函数
- io-nio-socket步步为营(六)SSL
- httpclient工具类
- 数据结构算法——单链表及其操作
- guid跟sequence做主键的比较
- Java核心代码(六) 桌面程序--记事本
- io-nio-socket步步为营(七) IO模型-心得体会
- js 比较日期大小
- storyboard点击背景关闭键盘
- java 代码片段
- GraphQL初探:从REST到GraphQL,更完善的数据查询定义
- Java设计模式-建造者模式