目录
排序:
一.简单选择排序
二.直接插入排序
三.希尔排序
四.冒泡排序
五.快速排序
六.归并排序
七.堆排序
八.基数排序
九.小结:
将一组任意顺序的数据元素或记录,按照其关键字排列成递增或递减的新序列的操作过程。
基本思路:每次从待排序的序列中选取关键字最小的记录,与当前排序序列的第一个记录交换位置,直到整个序列有序为止。
例:将5、8、2、4、6、1按升序排序。
排序 趟数 |
1 |
2 |
3 |
4 |
5 |
6 |
初始 |
5 |
8 |
2 |
4 |
6 |
1 |
1 |
1 |
8 |
2 |
4 |
6 |
5 |
2 |
1 |
2 |
8 |
4 |
6 |
5 |
3 |
1 |
2 |
4 |
8 |
6 |
5 |
4 |
1 |
2 |
4 |
5 |
6 |
8 |
5 |
1 |
2 |
4 |
5 |
6 |
8 |
过程说明:
一.排序1趟数过程说明:
首先将关键字一(5)与关键字二(8)比较大小,关键字一小,再将关键字一(5)与关键字三(2)比较大小,关键字三(2)小,再把关键字三与后面的关键字进行比较,最后把数值最小的关键字与关键字一交换数字,结果如排序趟数1所示。
排序2趟数过程说明:
二.经过趟数1的排序,关键字一的数值已经是最小的,所以从关键字二(8)开始排序;
将关键字二(8)与后序的关键字进行比较大小,将后序最小值的关键字与关键字二的数值交换位置。结果如趟数2所示:数值2为最小值,将数值2与数值8进行了交换位置。
三.趟数三的过程说明:
与上面的排序过程相同,前两个关键字的大小已经确定了,将关键字三(8)与后序全部的关键字进行比较大小,将最小值与关键字三(8)的位置进行互换。
四.
后序的排序同上述一样。最后结果如趟数5所示。
五.代码
void SelectSort(SqList *L) { /*对顺序表L作简单选择排序*/ RecordType temp; for(i=1; i
length; ++i) { /*选择第i个小的记录,并交换到位*/ j=i; /* j用于记录最小元素的位置*/ for(k=i+1; k<=L->length; k++) /*在L.r[i..L.length]中选择key最小的记录*/ if(L->r[k].key r[j].key) //遍历i后面的所有数,选择最小的数 j=k; //用j记录较小的那个数 if(i!=j) /*第i个小的记录L->r[j]与第i个记录交换*/ { temp=L->r[j]; //temp此时记录了较小的数 L->r[j]=L->r[i]; //把较大的数赋值给后面的那个数 L->r[i]=temp; //较小的赋值给i } } }/*SelectSort
六.算法评价
将一条待排序得记录按照其关键字的大小插入到已经有序的记录中,直到所有记录插入完成并且成为一个有序序列为止。
例:将 8、5、9、4、3、6、5* 按升序排序。
待插入元素位置序号 |
排序 趟数 |
R[0] |
R[1] |
R[2] |
R[3] |
R[4] |
R[5] |
R[6] |
R[7] |
初始 |
8 |
5 |
9 |
4 |
3 |
6 |
5* |
||
i=2 |
1 |
5 |
5 |
8 |
9 |
4 |
3 |
6 |
5* |
i=3 |
2 |
9 |
5 |
8 |
9 |
4 |
3 |
6 |
5* |
i=4 |
3 |
4 |
4 |
5 |
8 |
9 |
3 |
6 |
5* |
i=5 |
4 |
3 |
3 |
4 |
5 |
8 |
9 |
6 |
5* |
i=6 |
5 |
6 |
3 |
4 |
5 |
6 |
8 |
9 |
5* |
i=7 |
6 |
5* |
3 |
4 |
5 |
5* |
6 |
8 |
9 |
过程说明:
第一趟过程:
首先将R[2]赋值给R[0],然后把R[0]的值与R[1]进行比较,R[0] 第二趟排序: 将R[3]的值赋值给R[0],将R[0]的值与前两个值进行比较,R[0]>R[2],所以R[3]>R[2]排列顺序不变。 第三趟排序: 将R[4]的值赋值给R[0],R[0]与前三个值进行,首先从R[1]进行比较,R[0] 第四趟排序: 将R[5]的值赋值给R[0],然后从R[0]开始依次比较大小,R[0] 后序的排序方法重复以上操作。 代码: void InsertSort(SqList *L) 算法分析: 基本思路: 将整个待排序记录序列分割成若干子序列,对每个子序列进行直接插入排序,待整个序列中纪录“基本有序”时,再对全体记录进行一次直接插入排序。 具体操作: 选择一个增量序列T1......Tn,增序列是一个递减序列,且最后一个增量一定是1,即Tn=1; 按照增量序列个数n,进行n趟排序。 例:对关键字序列 T=(49,38,65,97, 76, 13, 27, 49*,55, 04)对应的记录进行希尔排序。 过程说明: 增量序列t=5时,具体分组情况为:49,13;38,27;65,49*;97,55;76,04; 将上述每个小组的数据进行直接插入排序,结果得到第一趟的排序结果。 增量序列t=3时,具体分组情况为:13,38;04,27;49*,49;38,55;27,65;49,97;55,76; 将上述每个小组中的数据进行直接插入排序,结果得到第二趟的排序结果。 第三趟的分组结果:13,04;04,49*;49*,38;38,27;27,49;49,55;55,65; 65,76;76,97;各个小组的直接插入排序同步进行,然后把各个小组的排序结果整合在一起。结果就得出第三趟的排序结果。 代码: 算法分析: 基本思路: 依次将待排序的记录相邻的关键字两两进行比较,如果后面的关键字小于前面的关键字的值,则进行交换记录的位置,没趟排序结束都会确定一个最大值在最后的位置。 例:使用冒泡排序方法将9、5、2、4按升序排序。 第一趟: 第二趟: 第三趟: 代码: 算法分析: 基本思路: 先从数列中选取一个数作为基数(该记录称为枢轴)。 2.将比基准大的数全部放到它的右边,小于或等于基准数的全放到它的左边。 3.再对左右两部分分重复第二步,直到各个区间只有一个数,达到整个序列有序。 轴元素的选取: 通常选取序列中的第一个元素, 选取原则: 1.首元素R[s]或者尾元素R[t]。 2.中值元素,取的是首元素,尾元素,中间位置元素三者中“中间大小”的元素。 3.随机元素R[i],i是s~t之间的一个随机整数。 例题: 第一趟排序结束 第一趟排序详解: 这里统一选取最左边的数为枢轴元素,以把49取出作为基准,左边low位置为空,所以这里先从high位置开始排序,49*=49,所以49*位置不动,默认如果当前位置未移动,则当前下标继续移动,所以high移动到27的位置,27<49,移动到low的位置。low与high交替移动,所以此时移动low的位置,low移动到38的位置,38<49,不需要移动,此时继续移动low的位置,low移动到65的位置,65>49,所以把65移动到high的位置。这时,移动high的位置,high移动到13的位置,13<49所以把13移动到low的位置,(交替移动位置)所以移动low的位置到97,97>49,所以移动到high的位置,接下来移动high的位置到76,76>49,所以不移动。此时再移动high位置,high位置与low位置重合,此时把基准数填入当前位置。 第一趟排序结束。 第二趟排序结束 第二趟排序详解: 经过第一趟排序,数组被分为两部分;49左边为都小于49的数,49右边为都大于49的数。 再分别对这两部分数进行快速排序。 首先对左部分进行排序。 选取左部分数组中,最左边的数作为基准,high位于13的位置,13<27,所以移动到low的位置,此时移动low的位置,38大于27,把38移动到high的位置。再移动high的位置,此时high的位置与low的位置重合,把27填入此时的位置。 这时,27左右两边的数组分别只有一个数(默认为有序),所以左部分数组排序结束。 第三趟排序结束 第三趟排序详解: 同样选取最左边的数作为基准数,然后按照以上原理进行移动。 第四趟排序结束 第四趟排序详解: 第三趟排序后,76把右部分数组分为两部分,做部分有两个数,所以还需要进行排序,选取最左边的数作为基准,high位于65的位置,65大于49,所以不需要进行排序,此时继续移动high的位置,high与low重合,所以填入基准数,排序结束。 代码: 算法分析: 后序内容持续完善更新。。。。。。。。
{ /*对顺序表L作插入排序*/
for(i=2; i<=L->length; ++i) //首先用第二个开始,与第一个数r[1]比较
if(L->r[i].key
{ /*当“<”时,才需将L->r[i]插入有序表*/
L->r[0]=L->r[i]; /*将待插入记录复制为哨兵 r[0]此时是较小的那个数*/
j=i-1; //j为i的前一个数
while(L->r[0].key
{ L->r[j+1]=L->r[j]; /*把大的那个值赋值给后面的位置*/
j--;
}
//循环后,经j--后,j的位置移动到了j的前一个位置,所以下面需要j++,把j恢复到原来的位置。
L->r[j+1]=L->r[0]; /*插入到正确位置*/
} /* if */
} /* InsertPass */
三.希尔排序
r[i]
0
1
2
3
4
5
6
7
8
9
10
初态:
49
38
65
97
76
13
27
49*
55
04
第一趟(t=5)
13
27
49*
55
04
49
38
65
97
76
第二趟(t=3)
13
04
49*
38
27
49
55
65
97
76
第三趟(t=1)
04
13
27
38
49*
49
55
65
76
97
void ShellInsert(SqList *L, int delta)
{ /*对L->r[ ]做一趟希尔插入排序,delta为增量*/
for(i=1+delta; i <= L->length; i++) /* 1+delta为第一个子序列的第二个元素的下标*/
if(L->r[i].key < L->r[i-delta].key)
{ L->r[0] = L->r[i]; /*备份r[i] */
for(j = i-delta; j > 0&&L->r[0].key < L->r[j].key; j-=delta)
L->r[j+delta] = L->r[j];
L->r[j+delta] = L->r[0];
}
}
void ShellSort(SqList *L)
/*对记录数组r做希尔排序,delta[0..t-1]为增量序列数组*/
{ for(i=0; i
四.冒泡排序
void BubbleSort(SqList *L)
{ /*对记录数组L->r做冒泡排序*/
RecordType temp;
n=L->length;
change=TRUE; /*设置交换标识为TRUE,便于进入循环*/
for(i=1; i<=n-1&&change; ++i)
{ change=FALSE; /*在第i趟中先设置记录交换标识为FALSE */
for(j=1; j<=n-i; ++j)
if(L->r[j].key > L->r[j+1].key) /*若相邻两记录逆序,交换 大的数字与下面小的数字互换位置*/
{ temp = L->r[j]; //依次执行冒泡原则,先是12比较 ;再23 ;之后34比较。。。。 ; 如此循环 ;把大的那个数,向下排序 ;
L->r[j] = L->r[j+1];
L->r[j+1] = temp;
change = TRUE; //第一次循环结束,true进入下一次循环
}
}
} /* BubbleSort */
//当i=1;进入第一次循环嵌套,j=1;对顶部的数进行冒泡排序,第一个数到达底部;
//当i=2;进入第二次循环嵌套,j=1; 同时i=2;(第一次循环后,已经有一个数排序完成,所以只需要比较n-i次)继续对顶部的数进行冒泡排序。。。;
//剩下最后一个数,不需要进行排序,已经是有序的;
五.快速排序
void QSort(RecordType R[], int s, int t)
{ /*对记录序列R[s..t]进行快速排序*/
if(s
六.归并排序
七.堆排序
八.基数排序
九.小结: