§9 内部排序
在《数据结构》里,排序一般分为:插入排序、交换排序、选择排序、归并排序和基数排序五种。
写在前面的话:
在看下面的各种算法之前,请先想想,如果给你一个无序的数列,你如何去排序?设计出你自己的算法。还有没有其它方法?相信自己的能力,排序算法是连小学生都可以设计出的!
不希望以后听到这样的话:“排序的算法我忘了……”,排序算法不是背出来的!
§9.1 插入排序(Insertion Sort)字符串截取数组
基本思想:
每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当位置,使数列依然有序;直到待排序数据元素全部插入完为止。
排序过程:
【示例】: [初始关键字] [49] 38 65 97 76 13 27 49
J=2(38) [38 49] 65 97 76 13 27 49
J=3(65) [38 49 65] 97 76 13 27 49
J=4(97) [38 49 65 97] 76 13 27 49
J=5(76) [38 49 65 76 97] 13 27 49
J=6(13) [13 38 49 65 76 97] 27 49
J=7(27) [13 27 38 49 65 76 97] 49
J=8(49) [13 27 38 49 49 65 76 97]
§9.2选择排序
基本思想:
每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
排序过程:
【示例】:初始关键字 [49 38 65 97 76 13 27 49]
第一趟排序后 13 [38 65 97 76 49 27 49]
第二趟排序后 13 27 [65 97 76 49 38 49]
第三趟排序后 13 27 38 [97 76 49 65 49]
第四趟排序后 13 27 38 49 [49 97 65 76]
第五趟排序后 13 27 38 49 49 [97 97 76]
第六趟排序后 13 27 38 49 49 76 [76 97]
第七趟排序后 13 27 38 49 49 76 76 [97]
最后排序结果 13 27 38 49 49 76 76 97
§9.3 冒泡排序 (BubbleSort)
基本思想:
两两比较待排序数据元素的大小,发现两个数据元素的次序相反时即进行交换,直到没有反序的数据元素为止。
排序过程:
设想被排序的数组R[1..N]垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上"漂浮",如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止。
【示例】:49 13 13 13 13 13 13 13
38 49 27 27 27 27 27 27
65 38 49 38 38 38 38 38
97 65 3849 49 49 49 49
76 97 6549 49 49 49 49
13 76 9765 65 65 65 65
27 27 7697 76 76 76 76
49 49 4976 97 97 97 97
【练习1】请分别用以上三种算法完成。
同学们进行了身体素质测量,其中立位体前屈的成绩是以XX . XX cm来记录的,这个成绩不可能超过100,当有可能为负数(当指尖碰不到足时),现有若干同学的成绩,请帮他们排序。
输入:第一行正整数 n (有n个同学)
第二行 n个成绩
输出: n个成绩从大到小的排列
§9.4 快速排序 (Quick Sort)
基本思想:
在当前无序区R[1..H]中任取一个数据元素作为比较的"基准元素",用此基准元素将当前无序区划分为左右两个较小的无序区:R[1..I-1]和R[I+1..H],且左边的无序子区中数据元素均小于等于基准元素,右边
的无序子区中数据元素均大于等于基准元素,而基准元素则位于最终排序的位置I 上,即R[1..I-1]≤R[I]≤R[I+1..H](1≤I≤H),当R[1..I-1]和R[I+1..H]均非空时,分别对它们进行上述的划分过程,直至所有无序子区中的数据元素均已排序为止。
排序过程:
——将数列从小到大排序
以第一个元素作为基准,设两指针i 和j ,初始时i 指向区间第一个元素,j 指向最末一个元素;先移动j 指针,如果j 元素比i 元素大,j 指针前移,否则若j 小于i ,则交换i 和j 。交换i 和j 后,移动i 指针,如果i 元素比j 元素小,i 指针后移,否则若i 大于j ,则交换i 和j 。再移动j 指针,……,轮流移动i 指针和j 指针,直到j = i 。
将数列分成两部分,分别进行上述过程。
【示例】: 初始关键字 ,j 指针左移 [49 38 65 97 76 13 27 49]
第一次交换后 ,j 指针不动,i 指针右移 [27 38 65 97 76 13 49 49] 第二次交换后 ,i 指针不动,j 指针左移 [27 38 49 97 76 13 65 49]
第三次交换后 ,j 指针不动,i 指针右移 [27 38 13 97 76 49 65 49]
第四次交换后,i 指针不动,j 指针左移 [27 38 13 49 76 97 65 49]
j 指针左移,遇i 指针 [27 38 13 49 76 97 65 49]
(递归过程)
初始关键字 [49 38 65 97 76 13 27 49]
一趟排序之后 [27 38 13] 49 [76 97 65 49]
二趟排序之后 [13] 27 [38] 49 [49 65]76 [97]
三趟排序之后 13 27 38 49 49 [65]76 97
最后的排序结果 13 27 38 49 49 65 76 97
i j i j i j j i i j j i
参考程序:
Procedure Parttion(L, H : Integer; var I : integer);
{对无序区R[L,H]做划分,I返回出本次划分后已被定位的基准元素的位置} begin
I:=L; J:=H; X:=R[I]; {初始化}
Repeat
While (R[J]>=X) And (I<J) Do J:=J–1;
{J指针左移,查第1个小于基准的元素} If I<J Then R[I]:=R[J]; {相当于交换R[I]和R[J]}
While (R[I]<=R[J]) And (I<J) Do I:=I+1;
{I指针右移,查第1个大于基准的元素} If I<J Then R[J]:=R[I];
Until I=J;
R[I]:=X; {基准X已被最终定位}
end; {Parttion}
Procedure QuickSort(S,T:Integer); {对R[S..T]快速排序}
begin
If S<T Then begin {当R[S..T]为空或只有一个元素是无需排序} Partion (S,T,I); {对R[S..T]做划分,返回I}
QuickSort (S,I-1); {递归处理左区间R[S,I-1]}
QuickSort (I+1,T); {递归处理右区间R[I+1,T]}
end;
end; {QuickSort}
【练习2】请将给出的单词按字典排序。(利用字符串比较)
输入:从文件word.in读入
第一行正整数n
以下n行每行一个单词
输出:写入文件word.out中
按字典排序,每行一个单词
§9.5 堆排序(Heap Sort)
基本思想:
堆排序是一树形选择排序,在排序过程中,将R[1..N]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。
堆的定义:
N个元素的序列K1, K2, K3, ……, Kn. 称为堆,当且仅当该序列满足特性: K i≤K2i K i≤K2i+1 (1≤ i≤ [N/2])
堆实质上是满足如下性质的二叉树:
1.是一棵完全二叉树;
2.树中任一结点的值均大于等于(小于等于)其孩子结点的值;
3.树根的值是最大的(最小的)
例如序列10, 15, 56, 25, 30, 70就是一个堆,它对应的完全二叉树如下图所示。
这种堆中根结点(称为堆顶)的关键字最小,我们把它称为小根堆。反之,若完全二叉树中任一非叶子结点的关键字均大于等于其孩子的关键字,则称之为大根堆。
这棵二叉树的存储,既可以用链表的方式存储,也可以用顺序表(一维数组S)的方式存储。采用顺序表的存储结构如上图所示,若某结点为S[ i ],则其左右子树分别为S[ 2i ]和S[ 2i+1 ]。
堆的调整:
在介绍从一个无序序列建堆的方法前,我们先看如何在一个已建成的堆中,若在输出堆顶的最小值之后,调整剩余的n-1个元素的序列,重又建成一个一个堆。
设图9-1为一个几建成的小根堆。
图9-1
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论