标签:
链表是一种常见的数据结构,在启发式搜索中我们常常需要把无序的链表,按照结点包含的元素数量从小到大排列整齐。面对链表排序问题,尤其是在链表节点是一张巨大的表的情况下,传统的交换法显得力不从心,而通过修改指针指向来使链表逻辑序列有序化是主要的解决途径。
如何对链表进行排序,可以借鉴我们所熟知的数组冒泡的思想。在数组冒泡中我们通过交换与移动两种操作把最值向后移动,在不同趟的排序中我们只需要维护一个变动的尾部。链表的冒泡思路与数组的冒泡是一致的,只不过具体的操作上有些不同,无论是交换还是移动操作,链表都需要当前节结点,下一个结点,上一个节点的协作,而要操作这些结点,就要有指向他们的三个指针。而操作这么多指针,最怕指歪了,所以分析的时候要仔细考虑所有情况。
我们首先来看下正常三交换的过程,先做交换:
然后是纠正指针:
当然最需要小心的是这种特殊情况,读者可以自己思考一下,处理过程和正常三交换基本相同:
三移动过程也不能大意,尤其是下面两种特殊情况:
另外关于维护一个变动的尾部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 }
标签:
原文地址:http://www.cnblogs.com/huaxiaforming/p/5195578.html