排序算法Word下载.docx
《排序算法Word下载.docx》由会员分享,可在线阅读,更多相关《排序算法Word下载.docx(29页珍藏版)》请在冰豆网上搜索。
![排序算法Word下载.docx](https://file1.bdocx.com/fileroot1/2023-1/7/fe5b20c9-c7ee-47f6-974a-3d5e353f7812/fe5b20c9-c7ee-47f6-974a-3d5e353f78121.gif)
5.
}
6.
endl;
7.}
8.
9.
10.void
InsertSort(int
n)
11.{
12.
i=
1;
i<
n;
i++){
13.
if(a[i]
a[i-1]){
//若第i个元素大于i-1元素,直接插入。
小于的话,移动有序表后插入
14.
i-1;
15.
x
=
a[i];
//复制为哨兵,即存储待排序元素
16.
a[i]
a[i-1];
//先后移一个元素
17.
while(x
a[j]){
//查找在有序表的插入位置
18.
a[j+1]
a[j];
19.
j--;
//元素后移
20.
21.
x;
//插入到正确位置
22.
23.
print(a,n,i);
//打印每趟排序的结果
24.
25.
26.}
27.
28.int
main(){
29.
a[8]
{3,1,5,7,2,4,9,6};
30.
InsertSort(a,8);
31.
print(a,8,8);
32.}
voidprint(inta[],intn,inti){cout<
i<
for(intj=0;
j<
j++){cout<
a[j]<
"
}cout<
}voidInsertSort(inta[],intn){for(inti=1;
i<
i++){if(a[i]<
a[i-1]){//若第i个元素大于i-1元素,直接插入。
小于的话,移动有序表后插入intj=i-1;
intx=a[i];
//复制为哨兵,即存储待排序元素a[i]=a[i-1];
//先后移一个元素while(x<
a[j]){//查找在有序表的插入位置a[j+1]=a[j];
j--;
//元素后移}a[j+1]=x;
//插入到正确位置}print(a,n,i);
//打印每趟排序的结果}}intmain(){inta[8]={3,1,5,7,2,4,9,6};
InsertSort(a,8);
print(a,8,8);
}
效率:
时间复杂度:
O(n^2).
其他的插入排序有二分插入排序,2-路插入排序。
2.插入排序—希尔排序(Shell`sSort)
希尔排序是1959年由D.L.Shell提出来的,相对直接排序有较大的改进。
希尔排序又叫缩小增量排序
基本思想:
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
操作方法:
1.选择一个增量序列t1,t2,…,tk,其中ti>
tj,tk=1;
2.按增量序列个数k,对序列进行k趟排序;
3.每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,分别对各子表进行直接插入排序。
仅增量因子为1时,整个序列作为一个表来处理,表长度即为整个序列的长度。
希尔排序的示例:
算法实现:
我们简单处理增量序列:
增量序列d={n/2,n/4,n/8.....1}n为要排序数的个数
先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。
继续不断缩小增量直至为1,最后使用直接插入排序完成排序。
8./**
*
直接插入排序的一般形式
10.
11.
@param
dk
缩小增量,如果是直接插入排序,dk=1
*/
15.void
ShellInsertSort(int
n,
dk)
16.{
dk;
++i){
a[i-dk]){
j
i-dk;
a[i-dk];
//首先后移一个元素
a[j+dk]
-=
26.
28.
print(a,
n,i
);
31.}
32.
33./**
34.
先按增量d(n/2,n为要排序数的个数进行希尔排序
35.
36.
37.void
shellSort(int
n){
38.
39.
n/2;
40.
while(
>
1
){
41.
ShellInsertSort(a,
dk);
42.
dk/2;
43.
44.}
45.int
46.
47.
//ShellInsertSort(a,8,1);
//直接插入排序
48.
shellSort(a,8);
//希尔插入排序
49.
50.}
}/***直接插入排序的一般形式**@paramintdk缩小增量,如果是直接插入排序,dk=1**/voidShellInsertSort(inta[],intn,intdk){for(inti=dk;
++i){if(a[i]<
a[i-dk]){//若第i个元素大于i-1元素,直接插入。
小于的话,移动有序表后插入intj=i-dk;
//复制为哨兵,即存储待排序元素a[i]=a[i-dk];
//首先后移一个元素while(x<
a[j]){//查找在有序表的插入位置a[j+dk]=a[j];
j-=dk;
//元素后移}a[j+dk]=x;
//插入到正确位置}print(a,n,i);
}}/***先按增量d(n/2,n为要排序数的个数进行希尔排序**/voidshellSort(inta[],intn){intdk=n/2;
while(dk>
=1){ShellInsertSort(a,n,dk);
dk=dk/2;
}}intmain(){inta[8]={3,1,5,7,2,4,9,6};
//ShellInsertSort(a,8,1);
//直接插入排序shellSort(a,8);
//希尔插入排序print(a,8,8);
希尔排序时效分析很难,关键码的比较次数与记录移动次数依赖于增量因子序列d的选取,特定情况下可以准确估算出关键码的比较次数和记录的移动次数。
目前还没有人给出选取最好的增量因子序列的方法。
增量因子序列可以有各种取法,有取奇数的,也有取质数的,但需要注意:
增量因子中除1外没有公因子,且最后一个增量因子必须为1。
希尔排序方法是一个不稳定的排序方法。
3.选择排序—简单选择排序(SimpleSelectionSort)
在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;
然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
简单选择排序的示例:
第一趟,从n个记录中找出关键码最小的记录与第一个记录交换;
第二趟,从第二个记录开始的n-1个记录中再选出关键码最小的记录与第二个记录交换;
以此类推.....
第i趟,则从第i个记录开始的n-i+1个记录中选出关键码最小的记录与第i个记录交换,直到整个序列按关键码有序。
第"
i+1
趟
数组的最小值
@return
数组的键值
13.int
SelectMinKey(int
i)
14.{
k
i;
j=i+1
++j)
{
if(a[k]
a[j])
j;
return
k;
20.}
22./**
选择排序
26.void
selectSort(int
key,
tmp;
++i)
key
SelectMinKey(a,
n,i);
//选择最小的元素
if(key
!
tmp
a[key];
a[key]
//最小元素与第i位置元素互换
33.
i);
35.}
36.int
37.
初始值:
endl<
selectSort(a,
8);
44.
45.}
i+1<
趟:
}/***数组的最小值**@returnint数组的键值*/intSelectMinKey(inta[],intn,inti){intk=i;
for(intj=i+1;
n;
++j){if(a[k]>
a[j])k=j;
}returnk;
}/***选择排序**/voidselectSort(inta[],intn){intkey,tmp;
for(inti=0;
++i){key=SelectMinKey(a,n,i);
//选择最小的元素if(key!
=i){tmp=a[i];
a[i]=a[key];
a[key]=tmp;
//最小元素与第i位置元素互换}print(a,n,i);
cout<
selectSort(a,8);
简单选择排序的改进——二元选择排序
简单选择排序,每趟循环只能确定一个元素排序后的定位。
我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。
改进后对n个数据进行排序,最多只需进行[n/2]趟循环即可。
具体实现如下:
SelectSort(int
r[],int
j
min
max,
for
(i=1
i++)
//
做不超过n/2趟选择排序
max
//分别记录最大和最小关键字记录位置
(j=
i+1;
n-i;
j++)
7.
if
(r[j]
r[max])
continue
(r[j]<
r[min])
//该交换操作还可分情况讨论以提高效率
r[i-1];
r[i-1]
r[min];
r[min]
r[n-i];
r[n-i]
r[max];
r[max]
19.}
voidSelectSort(intr[],intn){inti,j,min,max,tmp;
for(i=1;
=n/2;
i++){//做不超过n/2趟选择排序min=i;
max=i;
//分别记录最大和最小关键字记录位置for(j=i+1;
=n-i;
j++){if(r[j]>
r[max]){max=j;
continue;
}if(r[j]<
r[min]){min=j;
}}//该交换操作还可分情况讨论以提高效率tmp=r[i-1];
r[i-1]=r[min];
r[min]=tmp;
tmp=r[n-i];
r[n-i]=r[max];
r[max]=tmp;
}}
4.选择排序—堆排序(HeapSort)
堆排序是一种树形选择排序,是对直接选择排序的有效改进。
堆的定义如下:
具有n个元素的序列(k1,k2,...,kn),当且仅当满足
时称之为堆。
由堆的定义可以看出,堆顶元素(即第一个元素)必为最小项(小顶堆)。
若以一维数组存储一个堆,则堆对应一棵完全二叉树,且所有非叶结点的值均不大于(或不小于)其子女的值,根结点(堆顶元素)的值是最小(或最大)的。
如:
(a)大顶堆序列:
(96,83,27,38,11,09)
(b)
小顶堆序列:
(12,36,24,85,47,30,53,91)
初始时把要排序的n个数的序列看作是一棵顺序存储的二叉树(一维数组存储二叉树),调整它们的存储序,使之成为一个堆,将堆顶元素输出,得到n个元素中最小(或最大)的元素,这时堆的根节点的数最小(或者最大)。
然后对前面(n-1)个元素重新调整使之成为堆,输出堆顶元素,得到n个元素中次小(或次大)的元素。
依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。
称这个过程为堆排序。
因此,实现堆排序需解决两个问题:
1.如何将n个待排序的数建成堆;
2.输出堆顶元素后,怎样调整剩余n-1个元素,使其成为一个新堆。
首先讨论第二个问题:
输出堆顶元素后,对剩余n-1元素重新建成堆的调整过程。
调整小顶堆的方法:
1)设有m个元素的堆,输出堆顶元素后,剩下m-1个元素。
将堆底元素送入堆顶((最后一个元素与堆顶进行交换),堆被破坏,其原因仅是根结点不满足堆的性质。
2)将根结点与左、右子树中较小元素的进行交换。
3)若与左子树交换:
如果左子树堆被破坏,即左子树的根结点不满足堆的性质,则重复方法
(2).
4)若与右子树交换,如果右子树堆被破坏,即右子树的根结点不满足堆的性质。
则重复方法
(2).
5)继续对不满足堆性质的子树进行上述交换操作,直到叶子结点,堆被建成。
称这个自根结点到叶子结点的调整过程为筛选。
如图:
再讨论对n个元素初始建堆的过程。
建堆方法:
对初始序列建堆的过程,就是一个反复进行筛选的过程。
1)n个结点的完全二叉树,则最后一个结点是第个结点的子树。
2)筛选从第个结点为根的子树开始,该子树成为堆。
3)之后向前依次对各结点为根的子树进行筛选,使之成为堆,直到根结点。
如图建堆初始过程:
无序序列:
(49,38,65,97,76,13,27,49)
从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。
所以堆排序有两个函数组成。
一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。
6.}
已知H[s…m]除了H[s]
外均满足堆的定义
调整H[s],使其成为大顶堆.即将对第s个结点为根的子树筛选,
H是待调整的堆数组
s是待调整的数组元素的位置
length是数组的长度
17.void
HeapAdjust(int
H[],int
s,
length)
18.{
H[s];
child
2*s+1;
//左孩子结点的位置。
(i+1
为当前调整结点的右孩子结点的位置)
while
(child
if(child+1
length
&
H[