1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
| #include<string.h>
#include<ctype.h>
#include<malloc.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include "iostream"
//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status;
typedef int Boolean;
//对两个数值型关键字的比较
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
//待排记录的数据类型
#define MAXSIZE 20 //一个用作示例的小顺序表的最大长度
typedef int KeyType; //定义关键字类型为整型
typedef int InfoType; //定义其它数据项的类型
typedef struct {
KeyType key; //关键字项
InfoType otherinfo;//其他数据项
} RedType; //记录类型
typedef struct {
RedType r[MAXSIZE+1];//r[0]闲置或用作哨兵单元
int length;//顺序表长度
} SqList; //顺序表类型
typedef SqList HeapType; // 堆采用顺序表存储表示
//顺序表插入排序的函数
void InsertSort(SqList &L);
void BInsertSort(SqList &L);
void ShellInsert(SqList &L,int dk);
void ShellSort(SqList &L,int dlta[],int t);
//快速排序
int Partition(SqList &L,int low,int high);
void QSort(SqList &L,int low,int high);
void QuickSort(SqList &L);
//归并排序
void Merge(RedType SR[],RedType TR[],int i,int m,int n);
void MSort(RedType SR[],RedType TR1[],int s, int t);
void MergeSort(SqList &L);
//输出函数
void print(SqList L);
#define N 8
#define T 3
using namespace std;
int main() {
RedType d[N]= {{20,6},{52,1},{65,3},{88,9},{47,8},{22,4},{39,5},{74,7}};
int i;
SqList LL;
int dt[T]= {5,3,1}; // 增量序列数组
int choice;
s123:
cout<<"请选择要使用的排序算法:\n0..............退出\n";
cout<<"1..............插入排序\n2..............交换排序\n";
cout<<"3..............归并排序\n";
cin>>choice;
switch(choice) {
case 0:
break;
case 1: //插入排序
for(i=0; i<N; i++) //给 LL.r 赋值
LL.r[i+1]=d[i];
LL.length=N;
printf("直接插入排序前:\n");
print(LL);
InsertSort(LL);
printf("直接插入排序后:\n");
print(LL);
for(i=0; i<N; i++)
LL.r[i+1]=d[i];
LL.length=N;
printf("\n 折半插入排序前:\n");
print(LL);
BInsertSort(LL);
printf("折半插入排序后:\n");
print(LL);
for(i=0; i<N; i++)
LL.r[i+1]=d[i];
LL.length=N;
printf("\n 希尔排序前: \n");
print(LL);
ShellSort(LL,dt,T);
printf("希尔排序后: \n");
print(LL);
goto s123;
case 2: //交换排序
for(i=0; i<N; i++)
LL.r[i+1]=d[i];
LL.length=N;
printf("快速排序前:\n");
print(LL);
QuickSort(LL);
printf("快速排序后:\n");
print(LL);
goto s123;
case 3: //归并排序
for(i=0; i<N; i++)
LL.r[i+1]=d[i];
LL.length=N;
printf("归并排序前:\n");
print(LL);
MergeSort(LL);
printf("归并排序后:\n");
print(LL);
goto s123;
default:
cout<<"输入有误,请输入正确的选项!\n";
goto s123;
}
return 0;
}
//顺序表插入排序的函数(3 个)
//InsertSort
void InsertSort(SqList &L) {
// 对顺序表 L 作直接插入排序。
int i,j;
for(i=2; i<=L.length; ++i)
if(LT(L.r[i].key,L.r[i-1].key)) {
L.r[0]=L.r[i];
L.r[i]=L.r[i-1];
for(j=i-2; LT(L.r[0].key,L.r[j].key); --j)
L.r[j+1]=L.r[j];
L.r[j+1]=L.r[0];
}
}
//BInsertSort
void BInsertSort(SqList &L) {
//对顺序表 L 作折半插入排序。
int low,high,m;
for(int i=2; i<=L.length; ++i) {
L.r[0]=L.r[i];
low=1;
high=i-1;
while(low<=high) {
m=(low+high)/2;
if(LT(L.r[0].key,L.r[m].key))
high=m-1;
else
low=m+1;
}//while
for(int j=i-1; j>=high+1; --j)
L.r[j+1]=L.r[j];
L.r[high+1]=L.r[0];
}//for
}
//希尔排序
void ShellInsert(SqList &L,int dk) {
//对顺序表 L 作一趟希尔插入排序。本算法是和一趟直接插入排序相比,作了以下修改:
// 1.前后记录位置的增量是 dk,而不是 1;
// 2.r[0]只是暂存单元,不是哨兵。当 j<=0 时,插入位置已找到。
int i,j;
for(i=dk+1; i<=L.length; ++i)
if LT(L.r[i].key,L.r[i-dk].key) {
//需将 L.r[i]插入有序增量子表
L.r[0]=L.r[i]; //暂存在 L.r[0]
for(j=i-dk; j>0&<(L.r[0].key,L.r[j].key); j-=dk)
L.r[j+dk]=L.r[j]; //记录后移,查找插入位置
L.r[j+dk]=L.r[0]; //插入
}
}
void ShellSort(SqList &L,int dlta[],int t) {
//按增量序列 dlta[0..t-1]对顺序表 L 作希尔排序。
int k;
for(k=0; k<t; ++k) {
ShellInsert(L,dlta[k]); //一趟增量为 dlta[k]的插入排序
printf("第%d 趟排序结果: \n",k+1);
print(L);
}
}
//QuickSort
int Partition(SqList &L,int low,int high) {
//交换顺序表 L 中子表 r[low..high]的记录,枢轴记录到位,并返回其
//所在位置,此时在它之前(后)的记录均不大(小)于它。
KeyType pivotkey;
L.r[0]=L.r[low]; //用子表的第一个记录作枢轴记录
pivotkey=L.r[low].key; //枢轴记录关键字
while(low< high) {
//从表的两端交替地向中间扫描
while(low<high&&L.r[high].key>=pivotkey)
--high;
L.r[low]=L.r[high]; //将比枢轴记录小的记录移到低端
while(low<high&&L.r[low].key<=pivotkey)
++low;
L.r[high]=L.r[low]; //将比枢轴记录大的记录移到高端
}
L.r[low]=L.r[0]; //枢轴记录到位
return low; //返回枢轴位置
}
void QSort(SqList &L,int low,int high) {
//对顺序表 L 中的子序列 L.r[low..high]作快速排序。
if(low<high) {
int pivotloc;
pivotloc=Partition(L,low,high);
QSort(L,low,pivotloc-1);
QSort(L,pivotloc+1,high);
}//if
}//QSort
void QuickSort(SqList &L) {
//对顺序表 L 作快速排序。
QSort(L,1,L.length);
}
//归并排序
void Merge(RedType SR[],RedType TR[],int i,int m,int n) {
//将有序的 SR[i..m]和 SR[m+1..n]归并为有序的 TR[i..n]
int j,k,l;
for(j=m+1,k=i; i<=m&&j<=n; ++k) //将 SR 中记录由小到大地并入 TR
if LQ(SR[i].key,SR[j].key)
TR[k]=SR[i++];
else
TR[k]=SR[j++];
if(i<=m)
for(l=0; l<=m-i; l++)
TR[k+l]=SR[i+l]; //将剩余的 SR[i..m]复制到 TR
if(j<=n)
for(l=0; l<=n-j; l++)
TR[k+l]=SR[j+l]; //将剩余的 SR[j..n]复制到 TR
}
void MSort(RedType SR[],RedType TR1[],int s, int t) {
//将 SR[s..t]归并排序为 TR1[s..t]。
RedType TR2[MAXSIZE];
if(s==t)
TR1[s]=SR[s];
else {
int m=(s+t)/2;
MSort(SR,TR2,s,m);
MSort(SR,TR2,m+1,t);
Merge(TR2,TR1,s,m,t);
}
}
void MergeSort(SqList &L) {
//对顺序表 L 作归并排序。
MSort(L.r,L.r,1,L.length);
}
void print(SqList L) {
int i;
for(i=1; i<=L.length; i++)
printf(" (%d,%d) ",L.r[i].key,L.r[i].otherinfo);
printf("\n");
}
/*
实验结果:
请选择要使用的排序算法:
0..............退出
1..............插入排序
2..............交换排序
3..............归并排序
1
直接插入排序前:
(20,6) (52,1) (65,3) (88,9) (47,8) (22,4) (39,5) (74,7)
直接插入排序后:
(20,6) (22,4) (39,5) (47,8) (52,1) (65,3) (74,7) (88,9)
折半插入排序前:
(20,6) (52,1) (65,3) (88,9) (47,8) (22,4) (39,5) (74,7)
折半插入排序后:
(20,6) (22,4) (39,5) (47,8) (52,1) (65,3) (74,7) (88,9)
希尔排序前:
(20,6) (52,1) (65,3) (88,9) (47,8) (22,4) (39,5) (74,7)
第1 趟排序结果:
(20,6) (39,5) (65,3) (88,9) (47,8) (22,4) (52,1) (74,7)
第2 趟排序结果:
(20,6) (39,5) (22,4) (52,1) (47,8) (65,3) (88,9) (74,7)
第3 趟排序结果:
(20,6) (22,4) (39,5) (47,8) (52,1) (65,3) (74,7) (88,9)
希尔排序后:
(20,6) (22,4) (39,5) (47,8) (52,1) (65,3) (74,7) (88,9)
请选择要使用的排序算法:
0..............退出
1..............插入排序
2..............交换排序
3..............归并排序
2
快速排序前:
(20,6) (52,1) (65,3) (88,9) (47,8) (22,4) (39,5) (74,7)
快速排序后:
(20,6) (22,4) (39,5) (47,8) (52,1) (65,3) (74,7) (88,9)
请选择要使用的排序算法:
0..............退出
1..............插入排序
2..............交换排序
3..............归并排序
3
归并排序前:
(20,6) (52,1) (65,3) (88,9) (47,8) (22,4) (39,5) (74,7)
归并排序后:
(20,6) (22,4) (39,5) (47,8) (52,1) (65,3) (74,7) (88,9)
预习报告:
1.直接插入排序的核心思想就是:将数组中的所
有元素依次跟前面已经排好的元素相比较,如果
选择的元素比已排序的元素小,则交换,直到全
部元素都比较过。
2.尔排序的算法思想:将待排序数组按照步长gap
进行分组,然后将每组的元素利用直接插入排序的
方法进行排序;每次将增量折半减小,循环上述操作
;当增量=1时,利用直接插入,完成排序。
3.堆的概念
堆:本质是一种数组对象。特别重要的一点性质:
任意的叶子节点小于(或大于)它所有的父节
点。对此,又分为大顶堆和小顶堆,大顶堆
要求节点的元素都要大于其孩子,小顶堆要求节
点元素都小于其左右孩子,两者对左右孩子的大小
关系不做任何要求。
利用堆排序,就是基于大顶堆或者小顶堆的一种
排序方法。下面,我们通过大顶堆来实现。
实验心得:
1.在写冒泡排序的时候因为没有想到因为第一个位置
空闲不用,而导致写错了,是每次都把最小的冒到最上面
然后最大的就沉到最下面,从上向下就成了有序的。
所以冒泡排序思路为:
将序列当中的左右元素,依次比较,保证右边的元素始终大于左边的元素;
( 第一轮结束后,序列最后一个元素一定是当前序列的最大值;)
对序列当中剩下的n-1个元素再次执行步骤1。
对于长度为n的序列,一共需要执行n-1轮比较
(利用while循环可以减少执行次数)
2.快速排序的基本思想:挖坑填数+分治法
从序列当中选择一个基准数(pivot)
在这里我们选择序列当中第一个数最为基准数
将序列当中的所有数依次遍历,比基准数大的位于其右侧,比基准数小的位于其左侧
重复步骤1.2,直到所有子集当中只有一个元素为止。
用伪代码描述如下:
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中
3.基数排序:通过序列中各个元素的值,对排序的N个元素进行若干趟的“分配”与“收集”来实现排序。
分配:我们将L[i]中的元素取出,首先确定其个位上的数字,根据该数字分配到与之序号相同的桶中
收集:当序列中所有的元素都分配到对应的桶中,再按照顺序依次将桶中的元素收集形成新的一个待排序列L[ ]
对新形成的序列L[]重复执行分配和收集元素中的十位、百位...直到分配完该序列中的最高位,则排序结束
*/
|