堆排序之堆的概念—插入、删除、建堆

内容会持续更新,有错误的地方欢迎指正,谢谢!

堆的性质

  1. 性质:完全二叉树 或 近似完全二叉树(不是满二叉树的完全二叉树)。
  2. 分类:最大堆:父节点的值不小于子节点;最小堆:父节点的值不大于子节点。
  3. 左右子节点:没有大小的顺序。
  4. 堆的存储:
    一般都用数组来存储堆。下标为i的节点的父节点的下标为(i–1)/2。根节点的左右子节点下标分别为 2∗i+1 和 2∗i+2。例如:下标为0的节点左右子节点的下标分别为1和2。
  5. 堆的操作:插入、删除、建堆。

最小堆的图:
这里写图片描述

插入

原理:新元素必须插入到二叉树的末尾(即堆尾)。如果该数组构成的二叉树不满足堆的性质,则需要重新排列元素—“上浮”操作。

最小堆的插入操作图:
这里写图片描述

最大堆的插入操作的代码:

//非常建议各位看官根据对原理的理解,写出自己的代码,切忌看我的代码去理解算法,否则很快就会忘记!
void MaxHeapFixUp(int* array, int index) 
{
    //index为插入的节点的下标,则其父节点为(index-1)/2。
    int indexFather = (index - 1) / 2;
    int temp = 0;
    while(index!=0)
    {
        if (array[indexFather] < array[index])
        {
            temp = array[index];
            array[index] = array[indexFather];
            array[indexFather] = temp;
        }
        else
            break;
        index = indexFather;
        indexFather = (index - 1) / 2;
    }
}

删除

原理:删除操作必须删除该二叉树的根节点(即堆顶)。堆中最后一个元素用来补空,再重新排列元素—“下沉”操作。

最小堆的删除操作图:
这里写图片描述

删除操作的代码:

//非常建议各位看官根据对原理的理解,写出自己的代码,切忌看我的代码去理解算法,否则很快就会忘记!
void MaxHeapFixDown(int* array, int length, int index)
{
    ///index为待下沉的父节点的下标,其子节点为2*index+1和2*index+2。
    //本代码段只包含对根节点的下沉部分。
    int temp = array[index];
    int indexOfSon = 2 * index + 1;
    while (indexOfSon < length) 
    {
        if (indexOfSon + 1 < length&&array[indexOfSon + 1] > array[indexOfSon])
            ++indexOfSon;
        if (array[indexOfSon] < temp)
            break;
        array[index] = array[indexOfSon];
        index = indexOfSon;
        indexOfSon = 2 * index + 1;
    }
    array[index] = temp;
}

建堆(堆调整)

最小堆的初始图:
这里写图片描述

原理:很明显,对叶子结点来说,可以认为它已经是一个合法的堆了,即 20,60, 65,4, 49 都分别是一个合法的堆。只要从 a[4]=50 开始向下进行堆调整就可以了。然后再对 a[3]=30,a[2] = 17,a[1] = 12,a[0] = 9 分别作一次向下堆调整就可以了。

下面展示了建最小堆的步骤:
这里写图片描述

建最大堆的代码:

void MakeMaxHeap(int* array, int length)
{
    //length/2-1恒等于最后一个根节点的下标。
    for (int i = length / 2 - 1; i >= 0; --i) 
    {
        //调用删除(下沉)操作
        MaxHeapFixDown(array, 10, i);
    }
}

堆排序的实现

请查看我的另一篇博客,里面有详细地介绍:树形选择排序—堆排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值