选择排序和堆排序
2017-03-03 18:48
197 查看
选择排序
基本思想:每一趟在待排序的记录中选出关键字最小的记录,依次存放在已排好序的记录序列的最后,直到全部记录排序完为止。
1.直接选择排序
基本思想:每次从待排序的无序区中选择出关键字值最小的记录,将该记录与该区中的第一个记录交换位置。
2.堆排序
基本思想:在排序过程中,将记录数组R[0..n-1]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子节点之间的内在关系,
在当前无序区中选择关键字最大(或最小)的记录。
A|0
B|1 C|2
D|3 E|4
小根堆:k[i]<=K[2*i+1] && k[i]<=K[2*i+2]
大根堆:k[i]>=K[2*i+1] && k[i]>=K[2*i+2]
升序用大根堆,降序用小根堆。
运行结果:
堆排序过程:
下标: 0 1 2 3 4 5 6 7 8 9
数值: 5 4 3 2 1 6 7 5 2 8
初始建堆: i=4 5 4 3 2
8 6 7 5 2 1
i=3
5 4 3 5 8 6 7
2 2 1
i=2 5 4
7 5 8 6 3 2 2 1 2,5,6
i=1 5
8 7 5 4 6 3 2 2 1 1,3,4
i=0 8
5 7 5 4 6 3 2 2 1 0,1,2
<
b62e
p>
坐标从0开始的二叉树,已知子结点求父结点坐标为:parent=(i-1)/2;已知父结点求子结点的坐标为:left=2*i+1,right=2*i+2。
i=9
交换: 1 5 7 5 4 6 3 2 2 [8]
7 5 6 5 4
1 3 2 2 1
i=8
交换: 2 5 6 5 4 1 3 2 [7 8]
6 5 3 5 4
1 2 2 [7 8]
i=7
交换: 2 5 3 5 4 1 2 [6 7 8]
5
5 3 2 4 1 2 [6 7 8]
i=6
交换: 2 5 3 2 4 1 [5 6 7 8]
5 4 3 2
2 1 [5 6 7 8]
i=5
交换: 1 4 3 2 2 [5 5 6 7 8]
4 2 3
1 2 [5 5 6 7 8]
i=4
交换: 2 2 3 1 [4 5 5 6 7 8]
3 2 2 1 [4 5 5 6 7 8]
i=3
交换: 1 2 2 [3 4 5 5 6 7 8]
1 2 2 [3 4 5 5 6 7 8]
i=2
交换: 1 2 [2 3 4 5 5 6 7 8]
1 2 [2 3 4 5 5 6 7 8]
i=1
交换: 1 [2 2 3 4 5 5 6 7 8]
1 [2 2 3 4 5 5 6 7 8]
i=0
交换: [1 2 2 3 4 5 5 6 7 8]
[1 2 2 3 4 5 5 6 7 8]
基本思想:每一趟在待排序的记录中选出关键字最小的记录,依次存放在已排好序的记录序列的最后,直到全部记录排序完为止。
1.直接选择排序
基本思想:每次从待排序的无序区中选择出关键字值最小的记录,将该记录与该区中的第一个记录交换位置。
/* 直接选择排序 基本思想:每次从待排序的无序区中选择出关键字值最小的记录,将该记录与该区中的第一个记录交换位置。 */ void SelectSort(RecType R[],int n){ int i,j,min; RecType r; for(i=0;i<n-1;i++){//最后一个不用再选择最小的 min=i; for(j=i+1;j<n;j++){//i后直至n-1为无序区 if(R[j].key<R[min].key){ min=j; } } if(min!=i){ r=R[i]; R[i]=R[min];//把最小的赋值给i R[min]=r; } } }
2.堆排序
基本思想:在排序过程中,将记录数组R[0..n-1]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子节点之间的内在关系,
在当前无序区中选择关键字最大(或最小)的记录。
A|0
B|1 C|2
D|3 E|4
小根堆:k[i]<=K[2*i+1] && k[i]<=K[2*i+2]
大根堆:k[i]>=K[2*i+1] && k[i]>=K[2*i+2]
升序用大根堆,降序用小根堆。
/* 堆排序 基本思想:在排序过程中,将记录数组R[0..n-1]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子节点之间的内在关系, 在当前无序区中选择关键字最大(或最小)的记录。 A|0 B|1 C|2 D|3 E|4 小根堆:k[i]<=K[2*i+1] && k[i]<=K[2*i+2] 大根堆:k[i]>=K[2*i+1] && k[i]>=K[2*i+2] 升序用大根堆,降序用小根堆。 */ void Sift(RecType R[],int i,int h){//i是根堆的堆顶,一定从最大叶子层开始。 int j; RecType x=R[i]; j=2*i+1;//R[j]是左孩子] while(j<=h){//求根结点(i-1)/2 if(j<h && R[j].key<R[j+1].key) j++;//指向大的 if(x.key>=R[j].key)//父结点大于子结点 break; //父节点小于子结点,交换父结点和子结点 R[i]=R[j]; i=j; j=2*i+1; } R[i]=x; } void HeapSort(RecType R[],int n){ //对R[0..n-1]进行堆排序 int i; RecType r; //对初始数据建立大根堆 for(i=(n-1-1)/2;i>=0;i--) Sift(R,i,n-1); for(i=n-1;i>=0;i--){//对R[0..n-1] r=R[0]; R[0]=R[i]; R[i]=r; Sift(R,0,i-1);//0作为存放最大值的索引 } }完整代码:
#if ! defined(SELECTSORT_C)
#define SELECTSORT_C
#include<stdio.h>
#define MAXSIZE 100
typedef int KeyType;//关键字类型用来比较
typedef char InfoType;//其他类型的信息
typedef struct{
KeyType key;//排序用的关键字
InfoType other;//其他附属信息
}RecType;//记录类型
typedef RecType SeqList[MAXSIZE+1];//+1用来使[0]作为哨兵,但是在实际使用中往往不能使[0]作为哨兵
/*
选择排序
基本思想:每一趟在待排序的记录中选出关键字最小的记录,依次存放在已排好序的记录序列的最后,直到全部记录排序完为止。
*/
/* 直接选择排序 基本思想:每次从待排序的无序区中选择出关键字值最小的记录,将该记录与该区中的第一个记录交换位置。 */ void SelectSort(RecType R[],int n){ int i,j,min; RecType r; for(i=0;i<n-1;i++){//最后一个不用再选择最小的 min=i; for(j=i+1;j<n;j++){//i后直至n-1为无序区 if(R[j].key<R[min].key){ min=j; } } if(min!=i){ r=R[i]; R[i]=R[min];//把最小的赋值给i R[min]=r; } } }
void SelectSortTest(){
RecType SeqList[]={{5,'A'},{4,'B'},{3,'C'},{2,'D'},{1,'E'},{6,'F'},{7,'G'},{5,'H'},{2,'I'},{8,'J'},
{9,'K'},{10,'L'},{11,'M'},{12,'N'},{13,'O'},{14,'P'},{1,'Q'},{2,'R'},{3,'S'},{20,'T'}};
int i,n=10;
printf("直接选择排序前:\n");
for(i=0;i<n;i++){
printf("%2d,%c ",SeqList[i].key,SeqList[i].other);
if(i%10 == 9)
printf("\n");
}
printf("\n");
SelectSort(SeqList,n);
printf("直接选择排序后:\n");
for(i=0;i<n;i++){
printf("%2d,%c ",SeqList[i].key,SeqList[i].other);
if(i%10 == 9)
printf("\n");
}
printf("\n");
}
/* 堆排序 基本思想:在排序过程中,将记录数组R[0..n-1]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子节点之间的内在关系, 在当前无序区中选择关键字最大(或最小)的记录。 A|0 B|1 C|2 D|3 E|4 小根堆:k[i]<=K[2*i+1] && k[i]<=K[2*i+2] 大根堆:k[i]>=K[2*i+1] && k[i]>=K[2*i+2] 升序用大根堆,降序用小根堆。 */ void Sift(RecType R[],int i,int h){//i是根堆的堆顶,一定从最大叶子层开始。 int j; RecType x=R[i]; j=2*i+1;//R[j]是左孩子] while(j<=h){//求根结点(i-1)/2 if(j<h && R[j].key<R[j+1].key) j++;//指向大的 if(x.key>=R[j].key)//父结点大于子结点 break; //父节点小于子结点,交换父结点和子结点 R[i]=R[j]; i=j; j=2*i+1; } R[i]=x; } void HeapSort(RecType R[],int n){ //对R[0..n-1]进行堆排序 int i; RecType r; //对初始数据建立大根堆 for(i=(n-1-1)/2;i>=0;i--) Sift(R,i,n-1); for(i=n-1;i>=0;i--){//对R[0..n-1] r=R[0]; R[0]=R[i]; R[i]=r; Sift(R,0,i-1);//0作为存放最大值的索引 } }void HeapSortTest(){
RecType SeqList[]={{5,'A'},{4,'B'},{3,'C'},{2,'D'},{1,'E'},{6,'F'},{7,'G'},{5,'H'},{2,'I'},{8,'J'},
{9,'K'},{10,'L'},{11,'M'},{12,'N'},{13,'O'},{14,'P'},{1,'Q'},{2,'R'},{3,'S'},{20,'T'}};
int i,n=10;
printf("堆排序前:\n");
for(i=0;i<n;i++){
printf("%2d,%c ",SeqList[i].key,SeqList[i].other);
if(i%10 == 9)
printf("\n");
}
printf("\n");
HeapSort(SeqList,n);
printf("堆排序后:\n");
for(i=0;i<n;i++){
printf("%2d,%c ",SeqList[i].key,SeqList[i].other);
if(i%10 == 9)
printf("\n");
}
printf("\n");
}
int main(){
SelectSortTest();
printf("\n\n");
HeapSortTest();
return 0;
}
#endif
运行结果:
堆排序过程:
下标: 0 1 2 3 4 5 6 7 8 9
数值: 5 4 3 2 1 6 7 5 2 8
初始建堆: i=4 5 4 3 2
8 6 7 5 2 1
i=3
5 4 3 5 8 6 7
2 2 1
i=2 5 4
7 5 8 6 3 2 2 1 2,5,6
i=1 5
8 7 5 4 6 3 2 2 1 1,3,4
i=0 8
5 7 5 4 6 3 2 2 1 0,1,2
<
b62e
p>
坐标从0开始的二叉树,已知子结点求父结点坐标为:parent=(i-1)/2;已知父结点求子结点的坐标为:left=2*i+1,right=2*i+2。
i=9
交换: 1 5 7 5 4 6 3 2 2 [8]
7 5 6 5 4
1 3 2 2 1
i=8
交换: 2 5 6 5 4 1 3 2 [7 8]
6 5 3 5 4
1 2 2 [7 8]
i=7
交换: 2 5 3 5 4 1 2 [6 7 8]
5
5 3 2 4 1 2 [6 7 8]
i=6
交换: 2 5 3 2 4 1 [5 6 7 8]
5 4 3 2
2 1 [5 6 7 8]
i=5
交换: 1 4 3 2 2 [5 5 6 7 8]
4 2 3
1 2 [5 5 6 7 8]
i=4
交换: 2 2 3 1 [4 5 5 6 7 8]
3 2 2 1 [4 5 5 6 7 8]
i=3
交换: 1 2 2 [3 4 5 5 6 7 8]
1 2 2 [3 4 5 5 6 7 8]
i=2
交换: 1 2 [2 3 4 5 5 6 7 8]
1 2 [2 3 4 5 5 6 7 8]
i=1
交换: 1 [2 2 3 4 5 5 6 7 8]
1 [2 2 3 4 5 5 6 7 8]
i=0
交换: [1 2 2 3 4 5 5 6 7 8]
[1 2 2 3 4 5 5 6 7 8]
相关文章推荐
- 冒泡排序、插入排序、选择排序、希尔排序、堆排序、归并排序等常用排序算法的比较
- 排序算法2--简单选择排序、堆排序
- 常用的排序算法:冒泡,简单选择,直接插入,快速排序,堆排序
- 【排序】插入排序,希尔排序,选择排序,冒泡排序,堆排序详解及稳定性分析
- 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现)
- 2 -- 选择排序之堆排序
- 面试珠玑 快速排序、希尔排序、插入排序、选择排序、归并排序、堆排序总结
- 第十五周项目7—选择排序之堆排序
- 冒泡排序、选择排序、快速排序、插入排序(希尔排序)、堆排序(十大排序)
- 排序算法七:选择排序之堆排序
- 【Data_Structure笔记8】排序算法之【选择排序---堆排序】
- 选择排序之堆排序
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序
- 排序算法2--简单选择排序、堆排序
- 插入排序、选择排序、冒泡排序、快速排序、堆排序
- 选择排序之----堆排序
- 冒泡,选择,插入排序优化,堆排序和qsort的用法
- (12)选择排序之三 堆排序
- 几种基本排序的实现:选择排序,冒泡排序,插入排序,堆排序,快速排序,归并排序