【基础算法】-堆排序

1.首先了解堆是什么

堆是一种数据结构,一种叫做完全二叉树的数据结构。

2.堆的性质

在这里我们用到两种堆,其实也算是一种。

大顶堆:每个节点的值都大于或者等于它的左右子节点的值。

小顶堆:每个节点的值都小于或者等于它的左右子节点的值。

 如果我们把这两种对分别映射到数组中,就是一下两种:

从这里我们可以得出以下性质(重点

对于大顶堆:下标为i的节点的父节点下标:(i-1)/2【整数除法】

                      下标为i的节点的左孩子下标:i*2+1

                      下标为i的节点的右孩子下标:i*2+2

3.堆排序的基本思想

堆排序的基本思想是:

1.将待排序的序列构造成一个大顶堆,根据大顶堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素;

2.将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆;

3. 重复步骤2,如此反复,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值,然后把它放到大顶堆的尾部。最后,就得到一个有序的序列了。

假设有一个无需序列arr是:

 (1)将无序序列构建成一个大顶堆

     首先我们将现在的无序序列看成一个堆结构,一个没有规则的二叉树,将序列里的值按照从上往下,从左到右依次填充到二叉树中。

(2)从尾部向上观察,要维护大顶堆的性质

交换后的序列为:

(3)从尾部向上观察,继续维护大顶堆的性质

因为元素8没有子节点,所以继续比较下一个非叶子节点,元素值为5的节点,它的两个子节点值都比本身小,不需要调整;然后是元素值为4的节点,也就是根节点,因为9>4,所以需要调整位置

交换后的序列为:

(4) 从尾部向上观察,继续维护大顶堆的性质

此时,原来元素值为9的节点值变成4了,而且它本身有两个子节点,所以,这时需要再次调整该节点

交换后的序列为:

 到此,大顶堆就构建完毕了。满足大顶堆的性质。

(5)利用对排序的思想,将堆顶的元素之与尾部的元素交换-多次重复

然后将剩余的元素重新构建大顶堆,其实就是调整根节点以及其调整后影响的子节点,因为其他节点之前已经满足大顶堆性质。 

 然后,继续交换,堆顶节点元素值为8与当前尾部节点元素值为1的进行交换

                                                                  重新构建大顶堆

继续交换 

                  重新构建大顶堆

        继续交换 

 重新构建大顶堆

                                                                          继续交换

                                                                  

                                                                         构建大顶堆

                                                                         继续交换

                                                                   重新构建大顶堆

                                                                          继续交换

交换后的序列为:

 3.C语言实现堆排序

#include "../utils.h"

/**
 * 维护堆的性质
 * @param arr 存储堆的数组
 * @param len 数组长度
 * @param i 待维护节点的下标
 */
void heapify(int arr[], int len, int i)
{
    int largest = i;
    int lson = i * 2 + 1;
    int rson = i * 2 + 2;

    if (lson < len && arr[largest] < arr[lson])
        largest = lson;
    if (rson < len && arr[largest] < arr[rson])
        largest = rson;
    if (largest != i)
    {
        swap(&arr[largest], &arr[i]);
        heapify(arr, len, largest);
    }
}

// 堆排序入口
void heap_sort(int arr[], int len)
{
    int i;
    // 建堆
    for (i = len / 2 - 1; i >= 0; i--)
        heapify(arr, len, i);

    // 排序
    for (i = len - 1; i > 0; i--)
    {
        swap(&arr[i], &arr[0]);
        heapify(arr, i, 0);
    }
}

int main(int argc, char const *argv[])
{
    test(&heap_sort);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值