单向链表的排序
一.摘要
list容器封装了一个 sort() 函数对链表进行排序,以前没动手写过链表的排序,当初以为觉得这不是轻而易举吗?今天的 linux c编程实验 要用到链表,真的是我想当然了,花费了一下午和一晚上的时间。真的有点不可思议。总的来说,说起来容易也不容易,难也不难,只要你思路清晰,感觉还是很容易写出来的,前提是不要想着用最少的变量写出最短的代码?先写出来再想这些不行吗?
二.冒泡排序(C++描述)
下面给出普通排序算法(估计有点难看懂,建议看第二个):
注:front、middle、back 分别为前驱、中驱(自己编的)、后驱
1 void sort_list(list * &head) { //升序 2 /*第一版*/ 3 list *front, *middle, *back; 4 list *end=NULL;//保存内层循环的结束位置 5 while (head->next!=end) {//升序排列 6 front = head; 7 middle = head; 8 if (head->value > head->next->value) {//保持head永远指向链头 9 head = head->next; 10 } 11 int i = 0; 12 while (middle->next!=end) { 13 back = middle->next; 14 if (middle->value > back->value) {//交换middle和back 15 middle->next=back->next; 16 back->next = middle; 17 //因为初始状态的时候front和middl都是头结点,内层第一次循环不能让front->next = back,否则就相当于middle->next = back 18 if (i != 0) { 19 front->next = back; 20 } 21 front = back; 22 //上面的交换过程之后middle已经变成原来的back,也就是原来的下一个元素 23 } 24 else { 25 middle = middle->next; 26 if (i != 0) {//因为初始状态的时候front和middl都是头结点,内层第一次循环不需要移动front 27 front = front->next; 28 } 29 } 30 i=1; 31 } 32 end = middle; 33 } 34 }
上面的代码内层循环的每一次都令 front 和 middle 指向同一个元素,因此第一次循环和后面的循环还需要分情况处理(花了这么多时间,基本都花在这里),下面是附加空头结点辅助排序(内层循环不需要分情况处理,比上面的容易理解):
1 void sort_list(list * &head) { //升序 2 /*第二版while循环*/ 3 list *front, *middle, *back; 4 list *end = NULL;//保存内层循环的结束位置 5 /*插入空头结点*/ 6 /*list *t = new list; 7 t->next = head; 8 head = t;*/ 9 head = new list{ 0, head }; 10 while ((head->next)->next != end) {//升序排列 11 front = head; 12 middle = head->next; 13 while (middle->next != end) { 14 back = middle->next; 15 if (middle->value > back->value) {//交换middle和back 16 middle->next = back->next; 17 back->next = middle; 18 front->next = back; 19 //上面的交换过程之后middle已经变成原来的back,也就是原来的下一个元素 20 } 21 else { 22 middle = middle->next;//不需交换的话middle指向下一个元素 23 } 24 front = front->next;//前驱指向下一个元素 25 } 26 end = middle; 27 } 28 head = head->next; 29 }
附加头结点辅助排序的 for循环 代码(和上面的 第二版while循环 一模一样,估计直接看这个有点难理解,但是看起来紧凑、舒服):
1 void sort_list(list * &head) { //升序 2 /*第二版for循环*/ 3 list *front, *middle, *back; 4 list *end = NULL;//保存内层循环的结束位置 5 for (head = new list{ 0, head }; (head->next)->next != end; end = middle) { 6 for (front = head, middle = head->next; middle->next != end; front = front->next) { 7 back = middle->next; 8 if (middle->value > back->value) {//交换middle和back 9 middle->next = back->next; 10 back->next = middle; 11 front->next = back; 12 //上面的交换过程之后middle已经变成原来的back,也就是原来的下一个元素 13 } 14 else { 15 middle = middle->next;//不需交换的话middle指向下一个元素 16 } 17 } 18 } 19 head = head->next;//去除空头结点 20 }
完整代码:

1 #include<iostream> 2 #include<ctime> 3 using namespace std; 4 typedef struct s{ 5 int value; 6 struct s * next; 7 }list; 8 list * init_list() {//创建不带头结点的链表 9 srand((unsigned)time(NULL)); 10 list *head = new list; 11 list *p = head,*q; 12 for (int i = 0; i < 5; i++) { 13 q = new list; 14 q->value = rand(); 15 q->next = NULL; 16 p->next = q; 17 p = q; 18 } 19 head = head->next;//删去头节点 20 return head; 21 } 22 void sort_list(list * &head) { //升序 23 /*第二版for循环*/ 24 list *front, *middle, *back; 25 list *end = NULL;//保存内层循环的结束位置 26 for (head = new list{ 0, head }; (head->next)->next != end; end = middle) { 27 for (front = head, middle = head->next; middle->next != end; front = front->next) { 28 back = middle->next; 29 if (middle->value > back->value) {//交换middle和back 30 middle->next = back->next; 31 back->next = middle; 32 front->next = back; 33 //上面的交换过程之后middle已经变成原来的back,也就是原来的下一个元素 34 } 35 else { 36 middle = middle->next;//不需交换的话middle指向下一个元素 37 } 38 } 39 } 40 head = head->next;//去除空头结点 41 } 42 void print_list(list *p) { 43 while (p != NULL) { 44 cout << p->value << " "; 45 p = p->next; 46 } 47 cout << endl; 48 } 49 int main() { 50 /*创建链表*/ 51 list *head=init_list(); 52 /*打印随机数创建的链表*/ 53 print_list(head); 54 /*排序*/ 55 sort_list(head); 56 /*打印排序后的链表*/ 57 print_list(head); 58 system("pause"); 59 return 0; 60 }
运行结果:
三.总结
学业繁忙,就不详细讲过程了,图呢,当然就免了,先写着冒泡排序,以后需要其他的排序方法的时候再更新。
网上很多是值交换,这里就不再写了,相对来说简单一点,感觉也差不多,但是位置交换感觉还是必须掌握的,毕竟这是链表。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现