堆以及堆排序
1. 堆
二叉堆是一个数组,它可以被看成一个近似的完全二叉树。
二叉堆有两种形式:最大堆和最小堆。在最大堆中,父节点的值总是大于等于任何一个子节点的值。因此,堆中的最大元素放在根节点中,并且在任一子树中,该字数包含的所有节点的值都不大于该子树根节点的值。最小堆是指父节点的值总是小于或等于任一子节点的值。
在堆排序算法中,我们使用最大堆。最小堆通常用于构造优先队列。
2.堆的存储
一般都用数组来表示堆。一般位置0不用来存储元素,即存储区域为A[1,...,len]。所以对于一个节点。它的父节点的下标为2/i,左孩子的下标为2*i,右孩子的节点为2*i+1.
如果要使用下标为0的位置,那么父节点的下标就为(i-1)/2。它的左右子节点下标为2*i+1和2*i+2。
本文中将不使用0位置。
3. 向下调整
向下调整是为了维护堆的性质。它的输入为数组A和下标i。它首先看该节点是否大于其左右子节点的值,若不是,将左右子节点中较大值与之交换。交换后可能会破坏下一级的堆,于是继续采用上述方法构造下一级的堆,直到该节点为根的子结构成堆为止。时间复杂度为O(lgn)
1 void AdjustDown(ElemType A[], int k, int heap_size) { 2 int child; 3 ElemType tmp = A[i]; 4 5 for (int i = k << 1; i <= heap_size; i *= 2) { // 沿键值较大的子节点向下筛选 6 if (i < heap_size && A[i + 1] > A[i]) { 7 i++; 8 } 9 if (A[child] < tmp) { 10 A[k] = A[child]; //将A[child]调整到双亲的位置 11 k = i; //修改键值,以便继续向下筛选 12 } else { 13 break; 14 } 15 16 } 17 18 a[k] = tmp; //被筛选的值放入最终的位置 19 }
算法导论中给出的递归的方法:
1 inline int Left(int i) { 2 return i << 1; 3 } 4 5 inline int Right(int i) { 6 return i << 1 + 1; 7 } 8 9 void AdjustDown(int A[], int k, int heap_size) { 10 int left_child = Left(k); 11 int right_child = Right(k); 12 13 int largest = k; 14 15 if (left_child <= heap_size && A[left_child] > A[largest]) { 16 largest = leftc_child; 17 } 18 if (right_child <= heap_size && A[right_child] > A[largest]) { 19 largest = right_child; 20 } 21 22 if (largest != k) { 23 swap(A[k], A[largest]); 24 AdjustDown(A, largest, heap_size); 25 }
4.建堆
可以使用
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。