堆排序的代码实现

一.堆排序的简单讲解

     是一种基于二叉堆数据结构的比较排序算法。它利用了堆的性质来高效地完成排序任务。堆排序的主要思想是将待排序的数组构建成一个最大堆(或最小堆),然后通过不断提取堆顶元素(最大值或最小值)并重新调整堆,最终实现整个数组的有序排列。

     个人感觉堆排序就是采用了先建一个大堆,然后使得堆顶和数组的尾部进行交换,然后堆再进行向下调整,不断进行,使得整个数组都变为升序。   

基本原理

1. 堆的数组表示

二叉堆可以用数组表示,其中:

  • 索引为 i 的节点的左子节点索引为 2 * i + 1

  • 索引为 i 的节点的右子节点索引为 2 * i + 2

  • 索引为 i 的节点的父节点索引为 (i - 1) / 2

这种表示方式使得堆操作可以在数组上高效实现。

2. 堆操作

堆排序的核心操作包括:

  • 下沉操作:将一个节点下沉到合适的位置,以确保子树满足堆的性质。

  • 上浮操作:将一个节点上浮到合适的位置,以确保子树满足堆的性质(堆排序中较少使用)。

  • 构建堆:将一个无序数组构建成一个最大堆。

  • 提取堆顶元素:移除并返回堆顶元素(最大值或最小值),并重新调整堆。

 二.代码实现

  首先,我个人是喜欢先实现向上调整和向下调整,向上调整就是比较子节点和父节点的问题,如果子节点比父节点大,就进行交换,一直到堆顶 n = 0;

  void up(int* an, int n)
{
    while (n)
    {
        if (an[n] > an[n / 2])
        {
            int x = an[n];
            an[n] = an[n / 2];
            an[n / 2] = x;
            n = n / 2;
        }
        else
        {
            break;
        }
    }
}

向下调整,就是和自己最大的子节点比较,如果子节点大于父节点,则进行交换,反正则调整结束,但是要注意,这里可能存在只有一个孩子的情况,这个要单独拿出来比较

void down(int* an, int n, int z)
{
    if (n * 2 + 1 == z)
    {
        int g = n * 2 + 1;
        if (an[n] < an[g])
        {
            int x = an[n];
            an[n] = an[g];
            an[g] = x;
            n = g;
        }
    }
    while (n*2+1 < z)
    {
        int g;
        
        if (an[n * 2 + 1] > an[n * 2 + 2])
        {
            g = n * 2 + 1;
        }
        else
        {
            g = n * 2 + 2;
        }
        if (an[n] < an[g])
        {
            int x = an[n];
            an[n] = an[g];
            an[g] = x;
            n = g;
        }
        else
        {
            break;
        }
    }

}

然后开始排序,首先是建堆,建堆就是进行最后一个叶子节点进行向下调整,直到所有的非叶子节点都进行向下调整以后,堆也就建好了,建好堆以后,肯定会得到一个最大值,在顶端,然后将最大值和数组尾部的值进行交换,然后向下调整,直到完成结束,就实现了堆排序

void swap(int& x, int& y)
{
    int z = x;
    x = y;
    y = z;
}
void heapsort(int* an, int n)
{
    int x = n / 2 -1;
    while (x >= 0)
    {
        down(an, x,n-1);
        x--;
    }
    
    for (int i = 0; i < n-1; i++)
    {
        swap(an[0], an[n - i-1]);
        down(an, 0, n - i - 2);
    }
}

 

三.堆排序的性质

1. 时间复杂度
  • 构建最大堆:时间复杂度为 O(n)

  • 提取堆顶元素并调整堆:每次调整堆的时间复杂度为 O(log n),总共需要进行 n-1 次。

  • 总时间复杂度O(n log n)

2. 空间复杂度
  • 堆排序是原地排序算法,不需要额外的存储空间,空间复杂度为 O(1)

3. 稳定性
  • 堆排序是不稳定的排序算法。在堆化过程中,元素的相对顺序可能会改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值