小堆排序
堆排序是一种选择排序。
两个过程:1.初始建堆BuildHeap 2.移除根,重新建堆RebuildHeap
核心行为是:对于一个 除了根节点外,子树都是小根堆的数据进行根的调节。即AdjustHeap
AdjustHeap:从root往下都是满足小根堆,那么,需要对root数据进行调节。从root的child找,对比leftChild和rightChild,选两者中较小的和rootVal对比,
决定是否把child的数据赋给root结点,然后继续从childIndex往下搜,找到一个结点放置rootVal。
1.初始建堆, 叶子结点是满足小根堆的,从最后一个非叶子结点开始进行AdjustHeap,上溯到Root,初始建堆完成
2.移除根节点后,把最后一个叶子放入rootIndex,进行AdjustHeap的过程。不停的移除root,直到最后没数据
以下为测试代码:其中数组的第一个索引0没有使用。。
#include<iostream> using namespace std; void HeapAdjust(int arr[], int begIdx, int endIdx); void HeapBuild(int arr[], int begIdx, int endIdx); void HeapRebuild(int arr[], int begIdx, int endIdx); int const arrSize = 9; void main() { int arrTest[arrSize] = { 4,53,36,30,91,47,12,24,85 };//第一个参数不参与对比,因为树根节点索引为1 HeapBuild(arrTest, 1, arrSize - 1); HeapRebuild(arrTest, 1, arrSize - 1); return; } #pragma region 小根堆排序 /* *建堆,实际上是从叶子的父节点开始,进行从下往上的调堆过程 */ void HeapBuild(int arr[], int begIdx, int endIdx) { for (int i = endIdx / 2; i >= begIdx; --i) { HeapAdjust(arr, i, endIdx); } } /*初始堆后,移除root重建过程*/ void HeapRebuild(int arr[], int begIdx, int endIdx) { int rootVal = arr[begIdx]; arr[begIdx] = arr[endIdx]; arr[endIdx] = rootVal; int offsetNum = 0; for (int i = begIdx; i < endIdx - offsetNum; ++i, ++offsetNum) { int lastIdx = endIdx - offsetNum-1; HeapAdjust(arr, begIdx, lastIdx); //交换数据 int temp = arr[begIdx]; arr[begIdx] = arr[lastIdx]; arr[lastIdx] = temp; } } /*调堆的过程,除了根外,其他结点都是有序的*/ void HeapAdjust(int arr[], int begIdx, int endIdx) { int rootVal = arr[begIdx];//无序的根结点 int tempIdx = begIdx; //从子节点往下搜 for (int i = 2 * begIdx; i <= endIdx; i = 2 * i) { //对比左右子树,确保小的和父节点对比 if ((i + 1) <= endIdx&&arr[i] > arr[i + 1]) { i = i + 1; } if (rootVal <= arr[i]) { break; } else { arr[tempIdx] = arr[i];//数据上移动 tempIdx = i;//坑变了 } } arr[tempIdx] = rootVal;//最后把tempRootVal赋值给空余的坑下 } #pragma endregion