学习之后,自己练习手写一下排序算法,加深印象
原理:将待排序n个元素的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将它与堆末尾的元素交换后,移除。然后将剩下n-1个元素的序列重新构造成一个堆,这样就会得到这n-1个元素中最大值。如此反复交换根结点和构建新的堆,便能得到一个有序序列。
堆排序用到了完全二叉树的概念和性质,参见我的笔记https://blog.csdn.net/zjw_python/article/details/72808518
即若按照层序遍历的方式给结点编号,那么结点i
的左孩子为2i
,右孩子为2i+1
。(如果有左右孩子)
堆(Heap)是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
如何构造大顶堆呢?从下往上,从右到左,将每个非终端结点当做根结点,将其和其子树调整为大顶堆,我们先假设一个函数HeapAdjust(*L, int s, int maxIndex)
,其作用就是将序列中某个不符合堆结构的结点及其子树调整为堆结构,L
为传入的序列指针,s
为某个不满足堆结构的节点索引,maxIndex
为序列的最大索引。
堆排序的代码
HeapSort(struct a *L){
for (i = L->length/2; i>=1; i--){ //初始化序列为一个大顶堆,i等于n/2,因为
HeapAdjust(L, i, L->length); //包含n个元素的完全二叉树,拥有孩子结点的结点个数小于或等于⌊n/2⌋
}
for (i=L->length; i>1; i--){
swap(L, 1, i); //交换堆的根结点和最末端的结点
HeapAdjust(L, 1, i-1); //移除最末端的结点,重新调整为大顶堆
}
}
HeapAjust(struct a *L, int s, int maxIndex){
int j,temp;
temp = L->array[s]; //先将该不符合堆结构结点的值暂存起来
for (j=2*s; j<=maxIndex; j*=2){ //从该结点的左子节点开始,所以i=2*s,而节点的节点是以2的倍数增加的
if (j<maxIndex && L->array[j] < L->array[j+1]){ //比较左孩子结点和右孩子结点谁的值更大
j++; //j为具有更大值孩子节点的索引
}
if (temp > L->array[j]){ //如果当前结点的值比左右两孩子结点的值都要大
break; //说明当前结点符合堆结构,则退出循环
}
L->array[s] = L->array[j]; //将当前结点的值替换为左右孩子结点中更大的值
s = j; //将当前结点替换为孩子结点,以该孩子结点为根结点,重新循坏
}
L->array[s] = temp; //找到用于放置不符合堆结构的结点值的位置,替换之
}
完整的代码
#define MAXSIZE 10
#include <stdio.h>
struct a{
int array[MAXSIZE]; //数组用于存储排序数据
int length; //用于存储数组长度信息,
};
void init_array(struct a *L){ //初始化数组
int i;
L->length = MAXSIZE-1;
for (i=1;i<=L->length;i++){ //索引为0的项留作备用
scanf("%d",&(L->array[i]));
}
}
void swap(struct a *L,int i,int j){ //交换数组项
int temp = L->array[i];
L->array[i] = L->array[j];
L->array[j] = temp;
}
void print(struct a *L){ //打印数组项
int i;
for (i=1;i<=L->length;i++){
printf("%d ",L->array[i]);
}
}
void HeapAdjust(struct a *L, int s, int maxIndex){
int j,temp;
temp = L->array[s];
for (j=2*s; j <= maxIndex; j*=2){
if (j<maxIndex && L->array[j] < L->array[j+1]){
j++;
}
if (temp > L->array[j]){
break;
}
L->array[s] = L->array[j];
s = j;
}
L->array[s] = temp;
printf("\n构建堆:");
print(L);
}
void HeapSort(struct a *L){ //排序算法
int i;
for (i= L->length/2; i>=1; i--){
HeapAdjust(L,i,L->length);
}
for (i=L->length; i>1; i--){
swap(L,1,i);
HeapAdjust(L,1,i-1);
}
}
int main(){
struct a List;
init_array(&List);
printf("排序前:");
print(&List);
HeapSort(&List);
printf("\n排序后:");
print(&List);
return 0;
}
算法时间复杂度:O(nlogn)