堆排序

小堆排序

堆排序是一种选择排序。

两个过程: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
改变自己
原文地址:https://www.cnblogs.com/sun-shadow/p/6691163.html