单向链表的排序

一.摘要

  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 }
单向链表冒泡排序(完整代码)

运行结果:

 三.总结

  学业繁忙,就不详细讲过程了,图呢,当然就免了,先写着冒泡排序,以后需要其他的排序方法的时候再更新。

  网上很多是值交换,这里就不再写了,相对来说简单一点,感觉也差不多,但是位置交换感觉还是必须掌握的,毕竟这是链表。

posted @ 2020-05-18 01:24  小贼的自由  阅读(782)  评论(0编辑  收藏  举报