第六章
堆排序
堆可以被近似看成一个近似完全二叉树
以结点数为10的树为例
给定一个节点下标为i,则其父,子节点分别为
parent(i) return i/2 //父结点 left(i) return 2*i //左子结点 right(i) return 2*i+1 //右子结点
如 i= 2则其左子结点为4 右子节点为5 父节点为1
二叉堆可分为两种形式
最大堆 所有结点父结点要大于等于其自身
最小堆 所有结点父结点都要小于其自身
维护堆的性质
在输入新的数据时可能会导致堆违背最大堆性质通过调用一个函数,使以新的树位
根节点的子树重新遵循最大堆的性质。
原书伪代码
maxheap(A,i) l = left(i) //找出左右子结点的编号 r = right(i) if l <= A.heap-size and A[l] > A[i] //判断i与其左右子结点大小关系,并确定最大结点的编号 largest = l; else largest = i if r <= A.heap-size and A[r] > A[largest] largest = r if largest != i //如果最大结点不是i则交换i与其子结点的值,使其满足最大子树堆 exchange A[i] with A[largest] maxheap(A,largest) //调换之后其子节点也可能不满足最大堆性质,所以要逐层递归调用
建堆
在拥有维护堆性质工具后,我们可以进行最大堆的建立。
我们要对除叶子结点(即度为0的结点,无子树)的其他结点调用maxheap以维护
最大堆的性质。
n/2+1 to n 中的元素都是叶子结点
所以对1 to n/2所有结点调用维护函数
原书伪代码
buildmaxheap A.heap-size = A.length //实际元素数量 数组元素数量 for i = A.length/2 down to 1 maxheap(A,i)
利用最大堆我们可以进行排序,根据最大堆的性质,根结点总是最大的结点,所以
只要一次比较根节点,即可进行排序,并在过程中不断维护最大堆性质,以满足根节点最大,
注意 排过序的结点不应再被维护,所以应该将实际元素个数缩小
原书伪代码
heapsort(A) buildmaxheap(A) for i = A.length down to 2 exchange A[1] with A[i] A.heap-size = A.heap-size-1 maxheap(A,1)
C语言实现堆排序
#include<stdio.h> int truesize = 10; //实际堆中的元素(此程序堆中元素为10个等于数组元素数量 int parent(int i) //计算关系结点编号 { return i/2; } int left(int i) { return 2*i; } int right(int i) { return 2*i+1; } void maxheap(int a[],int i) //维护最大堆性质 { int largest; //储存最大结点编号 int l; //左结点 int r; //右 int exchange; l = left(i); r = right(i); if(a[l-1] > a[i-1]&& l <= truesize) //注意 C语言数组下标应该将i-1 largest = l; else largest = i; if(a[r-1] > a[largest-1]&&r <= truesize) largest = r; if(largest != i) { exchange = a[largest-1]; a[largest-1] = a[i-1]; a[i-1] = exchange; maxheap(a,largest); //逐层维护 } } void buildmaxheap(int a[]) //建立最大堆 { int n = 10; int i; for( i = n/2;i > 0;i--) { maxheap(a,i); } } void heapsort(int a[]) //堆排序 { int i = 10; int exchange; for(;i>1;i--) { exchange = a[0]; a[0] = a[i - 1]; a[i - 1] = exchange; truesize--; maxheap(a,1); } } int main() { int a[10]; int n,i; printf("scanf------------------\n"); for(i = 0;i < 10;i++) //输入堆中元素 scanf("%d",&a[i]); printf("maxheap------------------\n"); buildmaxheap(a); //建立最大堆 for(i = 0;i < 10;i++) printf("%d ",a[i]); //输出 heapsort(a); //堆排序 printf("\nresult------------------\n"); for(i = 0;i < 10;i++) printf("%d ",a[i]); //输出结果 return 0; }
运行样例