堆排序
堆
(二叉)堆数据结构是一种数组对象,可以看做成一个完全二叉树,除最后一层外树的每一次都必须填满。下面给出数组与树之间的关系图:
为了满足堆的有关性质,数组下标应从1开始记起。可以看出在这个所谓堆的二叉树中其子节点与父节点满足的关系为 parent(i) = i/2,即下标为 i 的节点的父节点为下标为 i/2 的节点;left(i) = i*2,即下标为 i 的节点的左子节点为下标为 i*2 的节点; right(i) = i*2+1,即下标为i的节点的右子节点为下标为 i*2+1 的节点。
大根堆
所谓的大根堆即父节点的值总是比子节点的值大,即可以推出 A[i] >= A[i*2] ,A[i] >= A[i*2+1] 恒成立,可以看出,其实在上面所述的堆中所给的图就是一个大根堆。
对于一个大根堆,如何来维护某节点不小于其子节点?如图:
若某节点并不与所想一样,即其比子节点小,那么我们必须对这个堆进行维护,正如图中所示,其过程为从该节点开始(对于此图而言,该节点为根节点),与其子节点进行比较,若不满足大根堆的条件,则将其与最大的数字所在节点进行交换,然后依次向下循环该过程,直到其不小于其子节点位置。
代码如下:
1 void MaxHeapify(int* A,int heapSize,int index) 2 { 3 int l,r; 4 int largest;//记录最大节点下标 5 int tmp; 6 7 largest = index; 8 l = left(index); 9 r = right(index); 10 11 if((l <= heapSize) && (A[l] > A[index])) 12 { 13 largest = l; 14 } 15 16 if((r <= heapSize) && (A[r] > A[largest])) 17 { 18 largest = r; 19 } 20 21 if( largest != index) 22 { 23 tmp = A[largest]; 24 A[largest] = A[index]; 25 A[index] = tmp; 26 MaxHeapify(A,heapSize,largest); 27 } 28 }
建堆
对于建立一个大根堆而言,对于我们得到的一个堆往往可能并不满足大根堆的条件,那么我们需要对其进行操作。
除了根节点之外的任意节点的父节点为可表示为 parent(i) = i/2,那么可以得出从堆中的最后一个节点的父节点开始维护这个大根堆,直到维护到这个堆的根节点为止,大根堆便可建成。
代码如下:
1 void BuildMaxHeap(int* A,int heapSize) 2 { 3 for(int i = heapSize/2 ; i >= 1; i--) 4 { 5 MaxHeapify(A,heapSize,i); 6 } 7 }
堆排序
大根堆的根节点往往是最大的,那么也就意味着说将根节点与最后一个节点交换,然后将最后一个节点排除在外,再次将堆调整成大根堆,循环此过程,直到这个堆中只包含根节点位置。大致过程如图所示:
代码如下:
1 void HeapSort(int* A,int heapSize) 2 { 3 int tmp; 4 for(int i = heapSize; i >= 2; i--) 5 { 6 tmp = A[i]; 7 A[i] = A[1]; 8 A[1] = tmp; 9 heapSize--;//堆长度减1 10 11 MaxHeapify(A,heapSize,1); 12 } 13 }