各种经典排序算法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
排 序
4、排序的稳定性
在待排序的文件中,若存在 多个关键字相同的记录,经 过排序后这些具有相同关键 字的记录之间的相对次序保 持不变,该排序方法是稳定 的; 若有: {R1 ,..., Ri,...,Rj,.....} 且关键字: Ki=Kj 排序后: i<>j
{ Ri,Rj,.....} 若具有相同关键字的记录之 间的相对次序发生变化,则 则称该排序结果具有稳定性。 称这种排序方法是不稳定的。
排 序
三、交换排序
两两比较待排序记录的关键字,发现两个记录次序 相反时即进行交换,直到没有反序的记录为止。
冒泡排序
快速排序
排 序
7.3.1 冒泡排序——基本思想和过程
假设在排序过程中,记录序列L.r[1..n]的状态为:
n-i+1
无序序列L.r[1..n-i+1] 有序序列 L.r[n-i+2..n]
有序序列L.r[1..i-1]
L.r[i]
无序序列 L.r[i..n]
有序序列L.r[1..i]
无序序列 L.r[i+1..n]
排 序
方法:
1.在L.r[1..i-1]中查找L.r[i]的插入位臵,
L.r[1..j] L.r[i] < L.r[j+1..i-1];
2.将L.r[j+1..i-1]中的所有记录均后移 一个位臵;
排 序
二、插入排序
每次将一个待排序的记录,按其关键字大小插入到前面 已经排好序的子文件中的适当位置,直到全部记录插入 完成为止。 把新元素(未排序的元素的关键字)逐个插入正在增长 的顺序表中。 寻找插入位置的方法:
线性插入排序
对半插入排序 希尔排序
排 序
1、线性插入排序
基本思想:每步将一个待排序的元素按其大小插入到 前面已排序的数据中的适当位置。重复该工作,直至 有序区包含所有元素。
#include "stdio.h" #define max 10 int data[max+1]; int index[max+1]; int i;
排 序 void shell_sort(a) int a[max+1]; { int i,j,n,m,skip; int alldone; for (i=1;i<=max;i++) index[i]=i; skip=max; while (skip>1) { skip=skip/2; do { alldone=1; for (j=1;j<=max-skip;j++) { i=j+skip; n=index[i]; m=index[j]; if (a[n]<a[m]) { index[i]=m; index[j]=n; alldone=0; } } } while (alldone==0); } }
线性插入排序示例
该算法适合于n 较 小的情况,时间复 杂度为O(n2).
排 序
插入算法
方法:Ki与Ki-1,K i-2,…K1依次比较,直到找到应插入的 位置。 void insertSort(RedType L[ ],int n)
{ int i ,j;
for(i=2; i<=n; i++) { L[0]=L[i]; for( j=i-1; L[0].key<L[j].key; j ) L[j+1]=L[j]; L[j+1]=L[0]; }} //记录后移 // 插入 // 作为监视哨
main() { int i; printf("请输入数据: "); for (i=1;i<=n;i++) scanf("%d",&ar[i]); d_insort(ar); printf("排序后的序列: "); for (i=1;i<=n;i++) { printf("%d |",ar[i]); } printf("\n"); } 运行结果: 请输入数据: 50 60 20 40 80 排序后的序列: 20 |40 |50 |60 |80 |
排 序
性能分析
最好情况(原始记录按关键字有序排列):O(n)
“比较”的次数: n
i 2
“移动”的次数: 0
1 n 1
最坏情况(原始记录按关键字逆序排列):O(n2) “比较”的次数: “移动”的次数:
n
(n 4)(n 1) (i 1) 2 i2
(n 4)(n 1) (i 1) 2 i 2
排 序
希尔插入排序——步骤
(1)首先选取一个整数d1<n(n为待排序数据的个数), 作为两个数据之间的距离,这样把全部数据分成d1个 组,凡是距离为d1的数据放在一个组里,在各组内进 行内部排序,直到各组排好序为止。
(2)从上述的结果序列出发,再选择d2<d1,重复上面的 分组与排序工作。 (3)依次取di+1<di,直到dm=1(设一共需要m次分组), 即所有数据放在一组中排序为止。此时,全部数据便 按次序排好了。
排 序
2. 希尔排序
运行结果:
请输入数据: 19 41 11 17 47 43 13 37 31 23
19 41 11 17 47 43 13 37 31 23 11 13 17 19 23 31 37 41 43 47 希尔排序的分析较为复杂,因为它的时间是所取 “增量”序列的函数,这涉及到一些数学上尚未解决的 难题。增量序列可以有各种取法,但需注意:应使增量 序列中的值没有除 1以外的公因子,并且最后一个增量 值必须等于1。
排 序
2. 排序的定义
假设含n个记录的序列为{ R1, R2, …, Rn }
其相应的关键字序列为 { K1, K2, …,Kn } 这些关键字相互之间可以进行比较,即在 它们之间存在着这样一个关系 : Kp1≤Kp2≤…≤Kpn
按此固有关系将上式记录序列重新排列为
{ Rp1, Rp2, …,Rpn } 的操作称作排序。
排 序
5、排序的分类
内部排序:是指在排序的整个过程中,数据全部存放 在计算机的内存储器里,并且在内存储器里调整数据 的位置;
当文件很大以致内存不足以存放全部数据时,在排序 过程中需要对外存进行存取访问,称这种借助于外存 储器进行排序的方法为外部排序。 注意: ① 内排序适用于记录个数不很多的小文件 ② 外排序则适用于记录个数太多,不能一次将其 全部记录放入内存的大文件。
排 序
本节基本内容与要求
基本内容 顺序查找、二分查找、二叉树查找以及散列表上查找 及算法思想 排序的基本概念以及选择、插入、交换和归并四类排 序的基本思想和算法 要求 掌握线性表、树和散列表(或称哈希表)的查找方法及 算法实现以及各种查找方法的应用 熟练掌握选择、插入、交换和归并四类排序的基本思 想和算法
n
结论:适用原始数据基本有序或数据量不大的情况。
排 序
2 希尔插入排序——算法思想
希尔排序(Shell’s method)又称为“缩小增量排序” , 本质上讲是插入排序,它是对线性插入排序的改进。
其基本思想是:
先取一个小于n的整数d1并作为第一个增量,将文件 的全部记录分成d1个组,所有距离为d1倍数的记录放在同 一个组中,在各组内进行直接插入排序;
字较小的记录在排序过程中是作跳跃式的移动。
另外,由于开始时增量的取值较大,每组中记录较少, 故排序比较快,随着增量值的逐步变小,每组中的记录逐渐
变多,但由于此时记录已基本有序了,因次在进行最后一趟
增量为1的插入排序时,只需作少量的比较和移动便可完成 排序,从而提高了排序速度。
排 序
希尔插入排序——性能效率
排 序
main() { printf("请输入数据: "); for (i=1;i<=max;i++) scanf("%d",&data[i]); printf("\n"); for (i=1;i<=max;i++) printf("%d ",data[i]); printf("\n"); shell_sort(data); for (i=1;i<=max;i++) printf("%d ",data[index[i]]); printf("\n"); }
排 序
3、排序的基本操作
排序的概念:就是要整理文件中的记录,使之按关键字 递增(或递减)次序排列起来。
排序过程的组成步骤:首先比较两个关键字的大小; 然 后将记录从一个位置移动到另一个位置。 对记录的关键字大小进行比较 将记录从一个位置移动到另一个位置 当待排序记录的关键字均不相同时,则排序结果是唯一 的,否则排序的结果不一定唯一。
排 序
1.4 内部排序
一、基本概念
二、插入排序 三、交换排序 四、选择排序 五、归并排序
排 序
一、基本概念
1. 排序的功能:将一个数据元素(或记录) 的任意序列,重新排成一个按关键字有序 的序列。
例如:下列是一组记录对应的关键字序列 (52, 49, 80, 36, 14, 58, 61, 23, 97, 75) 调整为 (14, 23, 36, 49, 52, 58, 61 ,75, 80, 97)
希尔插入排序——过程
设待排序共有10个记录,其关键字分别为47, 33, 61, 82, 71,
11, 25, 47, 57, 02,增量序列取值依次为5, 3, 1。
排 序
希尔插入排序——特点
希尔排序实质上还是一种插入排序,其主要特点是: 每一趟以不同的增量进行排序。在每趟的插入排序中,记录 的关键字是和同一组中的前一个关键字进行比较,所以关键
直接插入排序的程序: #include "stdio.h" #define n 5 int ar[n]; int c,t; void d_insort(a) int a[n]; { int i,j; for (i=2;i<=n;i++) { t=a[i]; j=i-1; while ((j>0) && (t<a[j])) {a[j+1]=a[j]; j=j-1;} a[j+1]=t; } }
3.将L.r[i] 插入到L.r[j+1]的位臵上。
具体方法:先将第一个数据看成是一个有序的子序列, 然后从第2个数据起逐个插入到这个有序的子序列中去, 相应的元素要移动。
排 序
例:
待排元素序列:[53] 第一次排序: 第二次排序: 第三次排序: 第四次排序: 第五次排序: [27 [27 [15 [15 [15 27 53] 36 27 27 27 36 36 53] 36 36 36 15 15 15 53] 53 42 69 69 69 69 69] 53 42 42 42 42 42 69] 对于有n个数 据元素的待排 序列,插入操 作要进行n-1 次
然后取第二个增量d2<d1,重复上述的分组和排序, 直至所取的增量dt=1 (dt<dt1<…<d2<d1)为止,此时,所 有的记录放在同一组中进行直接插入排序。
排 序
如何选择增量序列才能产生最好的排序效果,这个问
题至今没有得到解决。 希尔本人最初提出取 d1=n/2, d百度文库+1=di/2, dt=1,t=log2n。
希尔排序比直接插入排序的平均性能要好: 在最好情况(原始记录按关键字有序排列)下, 移动次数为0,比较次数界于n~ n2 之间。 在最坏情况(原始记录按关键字逆序排列)下, 移动次数和比较次数接近n2。 在平均情况下,移动次数和比较次数在O(n1.3) 左右,好于直接插入排序。
排 序
例1.19 希尔排序的程序
比较相邻记录,将关 键字最大的记录交换 到 n-i+1 的位臵上
无序序列L.r[1..n-i]
第 i 趟冒泡排序
有序序列 L.r[n-i+1..n]
排 序
7.3.1 冒泡排序——算法和性能分析
void BubbleSort(SqList *L) { for (i=L->length;i>1;--i){ for (j=1;j<i;++j) if (L->r[j+1]<L->r[j]){ Swap(L->r[j],L->r[j+1]); } } } 时间性能分析: 比较次数:最坏(n-1)+(n-2)+...+1; 最好: n-1 移动次数:最坏:3((n-1)+(n-2)+...+1);最好:0
排 序
哨兵(监视哨)
哨兵(监视哨)有两个作用 作为临时变量存放R[i](当前要进行比较的关键字)的 副本;
在查找循环中用来监视下标变量j是否越界。
R[0] R[1] 6 20 15 6 7 6 3 6 3 R[2] 6 20 15 7 6 R[3] R[4] 15 7 15 7 20 7 15 20 7 15 R[5] 3 3 3 3 20