zoukankan      html  css  js  c++  java
  • 单向链表的排序

    一.摘要

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

    运行结果:

     三.总结

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

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

  • 相关阅读:
    Python+request+unittest实现接口测试框架集成实例
    真正解决Jenkins安装插件总是报错的问题(网上查的解决方案都无效)
    Rancher 2.2.2
    Rancher管理k8s集群
    清理cosbench工具所占用磁盘空间的小脚本
    一个检查本机和远程机器的根目录所在磁盘的剩余空间的bash小脚本
    当df命令hang住了, 怎么办?
    OpenCV操作像素的几种方法(单个像素|操作多像素|遍历像素)
    OpenCV-颜色通道的分离、合并(转)
    ImageMagick 提取四通道png图片的alpha及magick使用
  • 原文地址:https://www.cnblogs.com/chasemeng/p/12908004.html
Copyright © 2011-2022 走看看