C++各类排序算法介绍PPT课件
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
}
r[i]=x;
qksort(r,t,j-1);
2021/2/10
qksort(r,j+1,w);
21
}
– 算法评价 • 时间复杂度 – 最好情况(每次总是选到中间值作枢轴) T(n)=O(nlog2n) – 最坏情况(每次总是选到最小或最大元素 作枢轴)T(n)=O(n² )
T(n)=O(n²)
• 根据“寻找”插入位置的方法不同,插入法可分为:直 插排序、二分插入排序、希尔排序。
• (1) 直接插入排序
– 若将一个未排序的元素L[i]插入到已排序的具有i-1个 元素的序列的适当位置,步骤如下:
• a. 从右向左顺序搜索已排序的序列,若已排序序 列中的元素比L[i]大,则后移一个位置,直至找到 一个元素L[j-1](0≤j-1≤i-1)的关键字值比L[i]的关键 字值小;
• 希尔排序可提高排序速度,因为 – 分组后n值减小,n² 更小,而T(n)=O(n² ),所 以T(n)从总体上看是减小了 – 关键字较小的记录跳跃式前移,在进行最后一 趟增量为1的插入排序时,序列已基本有序
• 增量序列取法 – 无除1以外的公因子 – 最后一个增量值必须为1
2021/2/10
14
关键字小,则可分别对这两部分记录进行排序,以达到 整个序列有序。 关键字通常取第一个记录的值为基准值。
– 排序过程:对r[s……t]中记录进行一趟快速排序,附设两 个指针i和j,设基准值记录rp=r[s],x=rp.key
• 初始时令i=s,j=t
• 首先从j所指位置向前搜索第一个关键字小于x的记录, 并和rp交换
9.3 交换排序
• (0) 基本思想:
– 两两比较待排序的数据元素的关键字,如果发生逆序, 则交换之,直到全部对象都排好序为止。
• (1) 冒泡排序过程
– 将第一个记录的关键字与第二个记录的关键字进行比 较,若为逆序r[1].key>r[2].key,则交换;然后比较 第二个记录与第三个记录;依次类推,直至第n-1个 记录和第n个记录比较为止——第一趟冒泡排序,结 果关键字最大的记录被安置在最后一个记录上。
contents
• 9.1 概述
• 9.2 插入排序
–1.直插排序
–2.二分插入排序
–3.希尔排序
• 9.3 交换排序
–1.冒泡排序
–2.快速排序
• 9.4 选择排序
–1.直选排序
–2.堆排序
• 9.5 归并排序
–1.二路归并排序
2021/2/10
1
9.1 概述
• 排序定义
–将一个数据元素(或记录)的任意序列,重新排列成一 个按关键字有序的序列叫~
– 对前n-1个记录进行第二趟冒泡排序,结果使关键字 次大的记录被安置在第n-1个记录位置。
– 重复上述过程,直到“在一趟排序过程中没有进行过
交换记录的操作”为止。
2021/2/10
15
16
13 27 30
第六趟
13 27 30 38
第五趟
3907 76
297 3706 65
1937 2776 3605 49
85 ) 20
85 ) 20
i=8 20 (6 13 20 30 39 42 70 85 )
2021/2/10
8
– 算法描述
void BinsertSort(int a[],const int n)
{
for(int i=1;i<n;i++) {
int b=a[i];
int low=0;
int high=i-1;
}
void ShellSort(int a[],int n,int dlta[],int t)
{
for(int k=0;k<t;k++)
ShellInsert(a,n,dlta[k]);
} 2021/2/10
13
– 希尔排序特点 • 子序列的构成不是简单的“逐段分割”,而是将相 隔某个增量的记录组成一个子序列。
二趟排序:13 4 48 38 27 49 55 65 97 76
2021/2/10
12
void ShellInsert(int a[], int n, int dk) {
for(int i=dk;i<n;i++) if(a[i]<a[i-dk]) { int b=a[i]; for(int j=i-dk;(j>=0)&&(b<a[j]);j-=dk) a[j+dk]=a[j]; a[j+dk]=b; }
三趟排序:4 13 27 38 48 49 55 65 76 97
2021/2/10
11
– 算法描述
#define T 3 int d[]={5,3,1};
例
1439 2378 6458 9575 746 1439 2378 6458 9575 746
j j j j ji i i i i
一趟排序:13 247 48 3585 247 49 5358 65 97 76 jj j j ji ij ij ij i i i
– 时间复杂度
• 若待排序记录按关键字从小到大排列(正序)
关键字比较次数: 记录移动次数:
n
1 n 1
i2 n
2 2(n 1)
i2
• 若待排序记录按关键字从大到小排列(逆序)
关键字比较次数:
n i (n 2)(n 1)
i2
2
记录移动次数:
n (i 1) (n 4)(n 1)
i2
• 再从i所指位置起向后搜索,找到第一个关键字大于x 的记录,和rp交换
• 重复上述两步,直至i==j为止
• 再分别对两个子序列进行快速排序,直到每个子序列
只含有一个记录为止
2021/2/10
19
x 例 初始关键字: 2479 38 146395 4997 76 941793 246795 50
i i i iij j j j j 完成一趟排序: ( 27 38 13) 49 (76 97 65 50)
{ int x=a[i]; //把待排序元素赋给 x //从a[i-2]开始比较
for(int j=i-1; (x<a[j])&&(j>=0); j--) a[j+1]=a[j]; //从a[i-1]开始后移一位
//直到找到一个元素,插入到正确位置
a[j+1]=x;
}
}
2021/2/10
6
• 算法评价
if(r[j].key>r[j+1].key) { //发生逆序
flag=1;
x=r[j];
r[j]=r[j+1];
r[j+1]=x;
} //交换,并标记发生了交换
m--;
}//while
} 2021/2/10
17
– 算法评价
• 时间复杂度
– 最好情况(正序)
比较次数:n-1
移动次数:0
– 最坏情况(逆序)
76 13 2675 3409 38
13 2479 308
13 2378
13
38 13 27 30 49
第四趟
38 49 13 27 30 65
第三趟
38 49 65 13 27 30 76 第二趟
38 49 65 76 13 27 30 97 第一趟
97
49
38
49 38 65 97 76 13 27 30 初始关键字
2
• 若待排序记录是随机的,取平均值
关键字比较次数: n2
4
记录移动次数: n2
4
T(n)=O(n²)
2021/2/10
7
• (2) 折半插入排序 – 排序过程:用折半查找方法确定插入位置的排序叫~
例 i=1
(30) 13 70 85 39 42 6 20
i=2 13 (13 30)C2h1/82_/150.c
22
9.4 选择排序
• (0) 选择排序原理: – 将待排序的结点分为已排序(初始为空)和未排序两组, 依次将未排序的结点中值最小的结点插入已排序的 组中。
2021/2/10
例
– 冒泡算法描述
void bubble_sort(JD r[], int n) {
int m,i,j,flag=1; //当flag为0则停止排序
JD x;
m=n-1;
while((m>0)&&(flag==1)) { //m表示趟数
flag=0; //开始时元素未交换
for(j=1; j<=m; j++)
while(low<=high) {
int m=(low+high)/2;
if(b<a[m])high=m-1;
else low=m+1;
}
for(int j=i-1;j>=high+1;j--)a[j+1]=a[j];
a[high+1]=b;
} } 2021/2/10
时间复杂度:T(n)=O(n² ) 9
比较次数: n1 (n i) 1 (n2 n)
i 1
2
移动次数:
3 n (n i) 3 (n2 n)
i 1
2
T(n)=O(n²)
20C2h1/82_/140.c
18
• (2) 快速排序
– 基本思想:通过一趟排序,将待排序记录分割成独立的 两部分,其中一部分记录的关键字均比另一部分记录的
• 排序分类
–按待排序记录所在位置
• 内部排序:待排序记录存放在内存
• 外部排序:排序过程中需对外存进行访问的排序
–按排序依据原则
• 插入排序:直接插入排序、折半插入排序、希尔排序
• 交换排序:冒泡排序、快速排序
• 选择排序:简单选择排序、堆排序
• 归并排序:2-路归并排序
• 2021/2/10 基数排序
取d1=5 一趟分组:49 38 65 97 76 13 27 48 55 4
一趟排序:13 27 48 55 4
取d2=3 二趟分组:13 27 48 55 4
49 38 65 97 76 49 38 65 97 76
二趟排序:13 4 48 38 27 49 55 65 97 76
取d3=1 三趟分组:13 27 48 55 4 49 38 65 97 76
分别进行快速排序: ( 13) 27 (38) 49 (50 65) 76 (97)
快速排序结束: 13 27 38 49 50 65 76 97
2021/2/10
20
– 快速算法描述
void qksort(JD r[], int t, int w)
{
int i, j, k;
JD x;
if(t>=w) return;
• b. 将L[i]插入表中第j个位置上,成为L[j]。
2021/2/10
4
例 i=1 (49) 38 65 97 76 13 27 i=2 38 (38 49) 65 97 76 13 27 i=3 65 (38 49 65) 97 76 13 27 i=4 97 (38 49 65 97) 76 13 27 i=5 76 (38 49 65 76 97) 13 27 i=6 13 (13 38 49 65 76 97) 27
…...
i=7 6 (6 13 30 39 42 70 85 ) 20
i=8 20 (6 s
i=8 20 (6 s
i=8 20 (6
i=8 20 (6
13 30 39 m
13 30 39 mj 13 30 39
s mj
13 30 39 js
42 70 42 70 42 70 42 70
85 ) 20 j 85 ) 20
• (3) 希尔排序(缩小增量法) – 排序过程:先取一个正整数d1<n,把所有相隔d1的 记录放一组,组内进行直接插入排序;然后取d2<d1, 重复上述分组和排序操作;直至di=1,即所有记录 放进一个组中排序为止。
2021/2/10
10
例 初始: 49 38 65 97 76 13 27 48 55 4
t中记录进行一趟快速排序附设两个指针i和j设基准值记录rprsxrpkey?初始时令isjt?首先从j所指位置向前搜索第一个关键字小于x的记录并和rp交换?再从i所指位置起向后搜索找到第一个关键字大于x的记录和rp交换?重复上述两步直至ij为止?再分别对两个子序列进行快速排序直到每个子序列只含有一个记录为止关键字通常取第一个记录的值为基准值
i=t; j=w; x=r[i];
while(i<j)
{
while((i<j)&&(r[j].key>=x.key)) j--;
if(i<j) { r[i]=r[j]; i++; }
while((i<j)&&(r[i].key<=x.key)) i++;
if(i<j) { r[j]=r[i]; j--; }
2
– 按排序所需工作量 • 简单的排序方法:T(n)=O(n²) • 先进的排序方法:T(n)=O(logn) • 基数排序:T(n)=O(d.n)
• 排序基本操作 – 比较两个关键字大小 – 将记录从一个位置移动到另一个位置
2021/2/10
3
9.2 插入排序
• 基本思想:每次将一个待排序的记录,按其关键字值的 大小插入到已经排好序的表中,直至全部插入完成。
i=7 27 (13 2378 4398 6459 6756 7967 ) 927 jjjjjj
排序结果:(13 27 38 49 65 76 97)
2021/2/10
5
void InsertSort(int a[],const int n)
{ for(int i=1;i<n;i++) //i表示插入次数,共进行n-1次插入 if(a[i]<a[i-1]) //将a[i]插入到有序区a[0],…,a[i-1]中, //且a[i]<a[i-1]