优化排序:
1.希尔排序:
Code:
1. //理论依据是直接插入排序法
2. #include <stdio.h>
3. #define N 11
4. #define MAXSIZE 100 //最大排序次数
5.
6. typedef struct
7. {
8. int key;
9. }DataType;
10. typedef struct
11. {
12. DataType r[N];
13. int length;
14. }SqList;
15.
16. void ShellInsert(SqList &L,int dk)//这是一趟希尔插入排序,增量为dk ,对比直接插入增量为1的来理解
17. {
18. int i,j;
19. for(i=dk+1;i<=L.length;++i)
20. {
21. if(L.r[i].key<L.r[i-dk].key)
22. {
23. L.r[0]=L.r[i];
24. for(j=i-dk;j>0&&L.r[0].key<L.r[j].key;j-=dk)
25. {
26. L.r[j+dk]=L.r[j];
27. }
28. L.r[j+dk]=L.r[0];
29. }
30. }
31. }
32.
33. void ShellSort(SqList &L,int dlta[],int t)
34. {
35. for(int k=0;k<t;++k)
36. ShellInsert(L,dlta[k]);
37. }
38.
39. int main(void)
40. {
41. int i,j;
42. SqList L;
43. L.length=N-1;
44. printf("请输入%d个关键字:/n",N-1);
45. for(i=1;i<N-1;i++)
46. {
47. scanf("%d ",&L.r[i].key);
48. }
49. scanf("%d",&L.r[i].key);
50.
51. int t=1; //用来代表排序的趟数
52. int dlta[MAXSIZE]; //增量的数组
53. dlta[0]=L.length/2;
54.
55. for(i=1;dlta[i-1]>=2;i++) //这个for循环用来计算循环的次数和给增量数组赋值,有点难度,想了蛮久
56. {
57. dlta[i]=dlta[i-1]/2;
58. t++;
59. }
60.
61. ShellSort(L,dlta,t);
62.
63. for(i=1;i<N-1;i++)
64. {
65. printf("%d ",L.r[i].key);
66. }
67. printf("%d/n",L.r[i].key);
68. return 0;
69. }
希尔排序是对直接插入排序的改进,它属于插入排序,是个不稳定的排序方法;
思路:先将整个待排序记录序列分割成为若干子序列分别进行直接插入排序,带整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
2.快排法:
Code:
1. /*
2. 一个acm题:
3. Sample Input
4. 2
5. 5 898
6. 3
7. 3 2 1
8. Sample Output
9. 5 898
10. 1 2 3
11. 你应当 用 O(n*lgn)的算法 避免 Time Limit Exceed
12. 你应当 用 scanf 不要使用cin 避免 Time Limit Exceed
13. */
14. /*
15. 快速排序的平均时间复杂为O(n*lgn),但是最坏情况(有序)时时间复杂度就变成了O(n*n)了,即此时蜕变成了普通排序。
16. 故快速排序比较适合杂乱无章的数据排序。
17. */
18. #include <stdio.h>
19. #include <stdlib.h>
20.
21. int Onefast(int a[],int low,int high) //优化,取a[0]为辅助空间
22. {
23. a[0]=a[low]; //这句不能放在while循环句里面 因为low是变化的
24. while(low<high)
25. {
26. while(low<high&&a[0]<=a[high]) --high;
27. a[low]=a[high];
28. while(low<high&&a[0]>=a[low]) ++low;
29. a[high]=a[low];
30. }
31. a[low]=a[0];
32. return low; //关键步骤:返回此时下标所在的位置
33. }
34.
35. void Fastsort(int a[],int low,int high)
36. {
37. int loc; //定义一个变量用来记录每趟快排后返回的位置
38. if(low<high) //递归一定是有出口的
39. {
40. loc=Onefast(a,low,high); //每次返回的low值得以保存
41. Fastsort(a,low,loc-1);
42. Fastsort(a,loc+1,high);
43. }
44. }
45. int main(void)
46. {
47. int i,n;
48. int *a;
49. while(scanf("%d",&n)!=EOF)
50. {
51. n=n+1;
52. a=(int *)malloc(sizeof(int)*n);
53. for(i=1;i<n-1;i++)
54. {
55. scanf("%d ",&a[i]);
56. }
57. scanf("%d",&a[i]);
58. Fastsort(a,1,n-1);
59. for(i=1;i<n-1;i++)
60. {
61. printf("%d ",a[i]);
62. }
63. printf("%d/n",a[i]);
64. }
65. return 0;
66. }
快排法是我接触的比较早的一个排序算法,是对冒泡排序的一种改进,使时间复杂度降低了。快排法是一种数据频繁跳跃“交换”---程序中优化成移动 的排序方法,所以是一种不稳定的排序。且快排法适合用于完全无序的关键字排序,对于有序的关键字,快排效率降低成普通排序。
3.堆排法:
Code:
1. #include <stdio.h>
2. #define MAX 101 //最大关键字系列长度为100
3.
4. typedef struct
5. {
6. int key;
7. }DataType;
8. typedef struct
9. {
10. DataType r[MAX];
11. int length;
12. }SqList;
13.
14. typedef SqList HeapType;
15.
16. void HeapAdjust(HeapType &H,int s,int m) //创建初始大顶堆,s为第一个下标,m为最后一个下标
17. {
18. int j;
19. H.r[0]=H.r[s];
20. for(j=2*s;j<=m;j*=2)
21. {
22. if(j<m&&H.r[j].key<H.r[j+1].key) //确保j为较大孩子的下标
23. {
24. ++j;
25. }
26. if(!(H.r[0].key<H.r[j].key)) //这里j必定为大孩子的下标
27. break;
28. H.r[s]=H.r[j];
29. s=j;
30. }
31. H.r[s]=H.r[0];
32. }
33.
34. void HeapSort(HeapType &H) //堆排序过程
35. {
36. int i;
37. for(i=H.length/2;i>0;--i) //这个for循环的作用是构建初始大顶堆,从第H.length/2个有叶子的结点开始
38. HeapAdjust(H,i,H.length);
39. for(i=H.length;i>1;--i) //这个for循环用来进行堆排序,i从最后一个数开始(由于我没用零的下标,所以可以取到H.length下标的数)
40. {
41. H.r[0]=H.r[1];
42. H.r[1]=H.r[i];
43. H.r[i]=H.r[0];
44. HeapAdjust(H,1,i-1); //排序从第一个开始而不是0(用做辅助空间)
45. }
46. }
47.
48. int main(void)
49. {
50. int n;
51. HeapType L;
52. printf("请输入关键字序列的长度:");
53. scanf("%d",&n);
54. L.length=n; //L.r[0]用来做辅助空间,其实是申请了n+1个空间
55. printf("请输入%d个关键字:",L.length);
56. for(int i=1;i<L.length;i++)
57. {
58. scanf("%d ",&L.r[i].key);
59. }
60. scanf("%d",&L.r[i].key);
61. HeapSort(L);
62. printf("排序后的关键字序列:/n");
63. for(i=1;i<L.length;i++)
64. {
65. printf("%d ",L.r[i].key);
66. }
67. printf("%d/n",L.r[i].key);
68. return 0;
69. }
每执行一趟堆排法之后,就将堆顶“最大”的数放到了有序区中,所以用大顶堆进行堆排法后得到的关键字序列将是升序的;堆排法在最坏的情况下,其时间复杂度也为O(n*logn),且仅需一个记录大小供交换的辅助存储空间。也是个不稳定的排序方法。对于n较大的文件比较有效。
4.归并排序:
Code:
1. #include <stdio.h>
2. #include <stdlib.h>
3. #define MAX 50 //最大序列长度
4. typedef struct
5. {
6. int key;
7. }RcdType;
8.
9. typedef struct
10. {
11. RcdType r[MAX];
12. int length;
13. }SqList;
14.
15. void Merge(RcdType SR[],RcdType TR[],int i,int m,int n) //归并
16. //这里不能写成&TR[],否则编译通不过(数据类型不一直),有待探讨
17. {//将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]中
18. for(int j=m+1,k=i;i<=m&&j<=n;k++)
19. {
20. if(SR[i].key<SR[j].key)
21. TR[k].key=SR[i++].key;
22. else
23. TR[k].key=SR[j++].key;
24. }
25. if(i<=m)
26. {
27. for(;i<=m;i++,k++) //i,j,k的初始值是链接到上面的
28. TR[k].key=SR[i].key;
29. }
30. if(j<=n)
31. {
32. for(;j<=n;j++,k++)
33. TR[k].key=SR[j].key;
34. }
35. }
36.
37.
38. void MSort(RcdType SR[],RcdType TR1[],int s,int t) //这里不能写成&TR1[],否则编译通不过,讨论为什么
39. {//将SR[s...t]归并为TR1[s..t]。
40.
41. int m;
42. RcdType *TR2;
43. TR2=(RcdType *)malloc(sizeof(RcdType)*(t-s+1)); //建立一个临时数组做辅助空间
44. if(s==t) //出口
45. TR1[s].key=SR[s].key;
46. else
47. {
48. m=(s+t)/2;
49. MSort(SR,TR2,s,m); //递归思想
50. MSort(SR,TR2,m+1,t);
51. Merge(TR2,TR1,s,m,t);
52. }
53. }
54.
55.
56. int main(void)
57. {
58. SqList L;
59. printf("请输入你要创建的关键字序列的长度:");
60. scanf("%d",&L.length);
61. printf("请输入%d个数:/n",L.length);
62.
63. for(int i=1;i<L.length;i++)
64. {
65. scanf("%d ",&L.r[i].key);
66. }
67. scanf("%d",&L.r[i].key);
68.
69. MSort(L.r,L.r,1,L.length);
70.
71. printf("排序后:/n");
72. for(i=1;i<L.length;i++)
73. {
74. printf("%d ",L.r[i].key);
75. }
76. printf("%d/n",L.r[i].key);
77. return 0;
78. }
2-路归并排序的核心操作是将数组中前后相邻的两个有序序列归并为一个有序序列。以前合并两个有序链表时用的方法其实就是这个思想。归并排序是一个有序的排序方法,但一般情况下,很少利用2-路归并排序法进行内部排序,一般用于外部排序。
5.基数排序
Code:
1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. /队列部分
5. #define OVERFLOW -2
6. #define ERROR 0;
7. typedef int QElemType;
8.
9. typedef struct QNode
10. {
11. QElemType data;
12. struct QNode *next;
13. }QNode,*QueuePtr;
14.
15. typedef struct
16. {
17. QueuePtr front;
18. QueuePtr rear;
19. }LinkQueue;
20.
21.
22.
23. //初始化
24. int InitQueue(LinkQueue &Q)
25. {
26. Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
27. if(!Q.front)exit(OVERFLOW);
28. Q.front->next=NULL;
29. return 1;
30. }
31.
32. int QueueEmpty(LinkQueue Q)
33. {
34. if(Q.front==Q.rear) //不要写成赋值符号
35. return 1; //空队列返回1,队列非空返回0
36. else
37. return 0;
38. }
39.
40.
41. //销毁队列
42. int DestroyQueue(LinkQueue &Q)
43. {
44. while(Q.front)
45. {
46. Q.rear=Q.front->next;
47. free(Q.front);
48. Q.front=Q.rear;
49. }
50. return 1;
51. }
52.
53.
54.
55. //从对头删除元素并用e返回其值
56. int DeQueue(LinkQueue &Q,QElemType &e)
57. {
58. QNode *p;
59. p=(QueuePtr)malloc(sizeof(QNode));
60. if(Q.front==Q.rear) return ERROR; //我汗 以前写的都将==写成了=号 无语
61. p=Q.front->next;
62. e=p->data;
63. Q.front->next=p->next;
64. if(Q.rear==p)Q.rear=Q.front; //还是等号与赋值符号的问题,这个是我易错点 千万要小心
65. free(p);
66. return 1;
67. }
68.
69. //从对尾插入元素
70. int EnQueue(LinkQueue &Q,QElemType e)
71. {
72. QueuePtr p;
73. p=(QueuePtr)malloc(sizeof(QNode));
74. if(!p)exit(OVERFLOW);
75. p->data=e;
76. p->next=NULL;
77. Q.rear->next=p;
78. Q.rear=p;
79. return 1;
80. }
81.
82. // 基数排序部分
83. #define N 8 //关键字个数
84. typedef int KeyType;
85. typedef struct
86. {
87. KeyType key;
88. }DataType;
89.
90.
91. int digit(KeyType key,int m,int r)
92. {
93. int i,d;
94. if(m==0) //从第0位开始的
95. return key%r;
96. d=r;
97. for(i=1;i<m;i++)
98. d*=r;
99. return ((int)(key/d)%r);
100. }
101.
102. void RadixSort(DataType L[],int n,int m,int r)
103. {//L中的关键字为m位r进制数,L的长度为n
104. LinkQueue *q;
105. int i,j,k;
106. q=(LinkQueue *)malloc(r*sizeof(LinkQueue));
107. for(i=0;i<r;i++)
108. InitQueue(q[i]);
109. for(i=0;i<m;i++)
110. {
111. for(j=0;j<n;j++)
112. { //取L[j].key的第i位数赋给k,k等于几就将L[j].key入对应q[k]的队列,按号入座
113. k=digit(L[j].key,i,r); //个人认为这步最关键
114. EnQueue(q[k],L[j].key);
115. }
116. k=0;
117.
118. for(j=0;j<r;j++)
119. {
120. for(;!QueueEmpty(q[j]);k++)
121. DeQueue(q[j],(L[k].key));
122. }
123. if(i!=m-1)
124. {
125. for(j=0;j<n-1;j++)
126. printf("%d/t",L[j].key);
127. printf("%d/n/n",L[j].key);
128. }
129. }
130. printf("经过%d次基数排序后已有序如下:/n",m);
131. for(j=0;j<n-1;j++)
132. printf("%d/t",L[j].key);
133. printf("%d/n/n",L[j].key);
134. for(i=0;i<r;i++)
135. DestroyQueue(q[i]);
136. }
137.
138. int main(void)
139. {
140. int m=3; //默认关键字最长位为四位
141. printf("请限定你要输入关键子的最长位数为:");
142. scanf("%d",&m);
143. DataType *L;
144. L=(DataType *)malloc(sizeof(DataType)*N);
145. printf("请输入%d个最长位数为%d关键字序列:/n",N,m);
146. fflush(stdin);
147. for(int i=0;i<N-1;i++)
148. {
149. scanf("%d ",&L[i].key);
150. }
151. scanf("%d",&L[i].key);
152. RadixSort(L,N,m,10);
153. return 0;
154. }
155.
算法思想:
1.设置r个队列,队列编号分别为0,1,2,…,r-1;
2.按数据元素关键字最低位上的数字值一次把n个数据元素分配到这r个队列中(入队列);
3.按照队列编号从小到大排序,将队列中的数据元素收集起来,形成一个新的数据元素序列,这两步就是第一趟基数排序;
4. 接着对第一趟基数排序后得到的数据元素序列,再按照数据元素关键字的次低位上的数字进行第二趟基数排序;
5. 如此反复,经过m趟基数排序后,就得到了数据元素的有序序列。
注:r是指进制数;m是值关键字位数的最大值。