从数组冒泡排序迁移到链表冒泡排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从数组冒泡排序迁移到链表冒泡排序相关的知识,希望对你有一定的参考价值。

  链表是一种常见的数据结构,在启发式搜索中我们常常需要把无序的链表,按照结点包含的元素数量从小到大排列整齐。面对链表排序问题,尤其是在链表节点是一张巨大的表的情况下,传统的交换法显得力不从心,而通过修改指针指向来使链表逻辑序列有序化是主要的解决途径。

技术分享

  如何对链表进行排序,可以借鉴我们所熟知的数组冒泡的思想。在数组冒泡中我们通过交换与移动两种操作把最值向后移动,在不同趟的排序中我们只需要维护一个变动的尾部。链表的冒泡思路与数组的冒泡是一致的,只不过具体的操作上有些不同,无论是交换还是移动操作,链表都需要当前节结点,下一个结点,上一个节点的协作,而要操作这些结点,就要有指向他们的三个指针。而操作这么多指针,最怕指歪了,所以分析的时候要仔细考虑所有情况。

  我们首先来看下正常三交换的过程,先做交换:

技术分享

  然后是纠正指针:

 技术分享

  当然最需要小心的是这种特殊情况,读者可以自己思考一下,处理过程和正常三交换基本相同:

 技术分享

  三移动过程也不能大意,尤其是下面两种特殊情况:

 技术分享

  另外关于维护一个变动的尾部tail,其实tail的作用是显示边界,tail后边的全是排好序的,不能动。有了tail,每趟排序就知道在哪里终止,而每趟排序又会有一个最值有序,所以tail在不停向前移动,tail自己是不能前移的,好在它前面有个right,所以tail总是跟随right。

技术分享

 

最后附上源码:

  1 /*************************************************************** 
  2 程序作者:yin
  3 创建日期:2016-2-16
  4 程序说明:链表冒泡,与数组冒泡不同的是交换与移动需要三个指针的协
  5 作,即三交换与三移动,并且交换与移动过程要验证合法性,防止指针指
  6 歪了。程序可做通用修改,替换sort()中节点类型Node与节点的键值data,
  7 外部给sort()传指针地址即可使用。
  8  ***************************************************************/
  9 /*************************************************************** 
 10 修改作者:yin
 11 修改日期:2016-2-17 
 12 修改说明:
 13 1.完善调试显示与注释
 14 后续改进:暂无
 15  ***************************************************************/
 16 #include<stdio.h>
 17 #include<stdlib.h>
 18 typedef struct NODE
 19 {
 20     int data;
 21     struct NODE * next;
 22 }Node;
 23 void sort(Node **h)
 24 {
 25     //操纵*h与head等效
 26     Node* left=NULL;
 27     Node* cur=NULL;
 28     Node* right=NULL;
 29     //每趟冒泡都有一个变动的尾部tail
 30     for(Node* tail=NULL;tail!=(*h)->next;)//(*h)->next指向的是第二元素,当tail指向第二元素整个程序终止
 31     {
 32         //每趟冒泡排序的开始点
 33         
 34         //printf("此趟冒泡排序开始......\n");//#####调试显示#####
 35         //每趟冒泡起点初始化,都是从第一个点开始的 
 36         left=NULL;
 37         cur=*h;
 38         right=cur->next;
 39         while(1) 
 40         {
 41             if(cur->data > right->data)//逆序,三交换 
 42             {
 43                 //printf("now   exchange (%2d) and (%2d)\n",cur->data,right->data);//#####调试显示#####
 44                 //交换
 45                 cur->next=right->next;
 46                 right->next=cur;
 47                 if(left==NULL) *h=right;
 48                 else left->next=right;;    
 49                 //纠正
 50                 cur=right;
 51                 right=right->next;
 52                 //printf("after exchange (%2d) and (%2d)\n",cur->data,right->data);//#####调试显示#####        
 53             }
 54             if(right->next!=tail)//三移动为下一次做准备
 55             {    
 56                 if(left!=NULL)    left=left->next;
 57                 else              left=cur;    
 58                 cur=cur->next;
 59                 right=right->next;
 60             }
 61             else break;
 62         }
 63         
 64         tail=right;    //一个变动的尾部    
 65         
 66         //每趟冒泡排序的结束点
 67         
 68         //#####调试显示#####
 69     /*     printf("此趟冒泡排序的结果\n");
 70         for(Node *p=*h;p!=NULL;p=p->next)
 71             printf("(%2d)  ",p->data);
 72         printf("\n"); */    
 73     }
 74 }
 75 int main()
 76 {
 77     Node *head=NULL;
 78     int dataarray[10]={6,9,8,3,10,5,4,7,2,1};
 79     
 80     Node*pt=NULL;
 81     for(int i=0;i<10;i++)
 82     {
 83         //开空间,需要引用 stdlib.h
 84         Node *temp=(Node*)malloc(sizeof(Node));
 85         temp->data=dataarray[i];
 86         temp->next=NULL;
 87         //连接
 88         if(i==0) 
 89         {
 90             head=temp;
 91             pt=temp;
 92         }    
 93         else
 94         {
 95             pt->next=temp;
 96             pt=pt->next;
 97         }
 98     }
 99                 printf("--------------------------------------------------------------------\n");
100                 printf("初始数据序列:\n");
101                 for(Node *p=head;p!=NULL;p=p->next)
102                     printf("(%2d)   ",p->data);
103                 printf("\n");
104                 printf("--------------------------------------------------------------------\n");
105     
106     sort(&head);//测试sort
107     
108                 printf("--------------------------------------------------------------------\n");
109                 printf("链表冒泡结果:\n");
110                 for(Node *p=head;p!=NULL;p=p->next)
111                     printf("(%2d)   ",p->data);
112                 printf("\n");
113                 printf("--------------------------------------------------------------------\n");
114 }

 

以上是关于从数组冒泡排序迁移到链表冒泡排序的主要内容,如果未能解决你的问题,请参考以下文章

经典算法学习——链表实现冒泡排序

常用排序算法之冒泡排序选择排序

链表的三种插入排序+冒泡排序

经典算法学习——非循环双向链表实现冒泡排序(不带头结点)

十大排序算法--冒泡排序

冒泡排序和鸡尾酒排序的代码分析