基本思想:每一趟在待排序的记录中选出关键字最小的记录,依次存放在已排好序的记录序列的最后,直到全部记录排序完为止。
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
坐标从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]