堆排序 C++代码实现及思想 排序过程输出 恋上数据结构笔记

复习梗概

什么是堆思想?

  1. 最大堆:树形结构,每一个结点元素都比子结点大
  2. 堆常常用动态数组存储
  3. 二叉最大堆能够应用于动态数组,是因为应用了完全二叉树的两个特性:i为当前结点序号,左子结点 = 2i+1,右子结点=2i+2,父结点=floor((i-1)/2),这个是根结点序号为0的情况,这个特质不用死记硬背,想用的时候画个图自己标下序号就试出来了
  4. 完全二叉树,共n个结点,叶子结点序号从n/2开始(根结点为0)
  5. 堆常常用来解决求数组里的最大值,最小值问题(Top K)
  6. 堆的笔记 恋上数据结构

堆排序算法怎么来的?

选择排序算法优化来的

相比冒泡排序,选择排序无法在内循环过程中,通过比较确定前面是否已经形成有序序列,因此我认为这里难以优化
但实际上可以从另一个地方优化:即选取未排序序列最大值这个过程,如果用堆完成的话,时间复杂度只有O(logn)(主要是下滤,结点的高度logn),整体复杂度O(nlogn)
因此,优化后的选择排序算法 即为 堆排序


什么是下滤?代码

  1. 为了确保堆的特性
  2. 使不符合堆的特性的某个元素与其子结点元素比较,若子结点元素较大,则交换二者,更新二者索引,不断重复与子结点比较,直到没有子结点或已经比子结点大
  3. 这里如何处理只有左子结点的结点?看代码
void siftDown(vector<int> &array, int index, int end)
{
   
    //! 这里指对array的index元素进行下滤操作,这里的end指的是未排序的序列的末尾元素的index,因为vector容器的size是私有的不能改
    int biggerChildIndex = index * 2 + 1;
    while (biggerChildIndex <= end)
    {
   
        if (biggerChildIndex + 1 <= end && array[biggerChildIndex] < array[biggerChildIndex + 1])
        {
    // if确保若该结点存在右子结点,且右结点值大于左结点,则biggerChildIndex更新为右结点的index
            //若没有右子结点,该语句不会触发,且biggerChildIndex默认就是左子结点,妙啊
            biggerChildIndex++;
        }
        if (array[index] < array[biggerChildIndex])
        {
   
            int temp = array[index];
            array[index] = array[biggerChildIndex]; //发现子结点大于该结点,进行调换
            array[biggerChildIndex] = temp;

            index = biggerChildIndex;
            biggerChildIndex = index * 2 + 1; //若发生下滤,则更新index和childIndex,进行下一次下滤比较
        }
        else
        {
   
            break; //若子结点大于该结点,停止本次下滤
        }
    }
}

什么是建堆?代码

  1. 用一段数组作为输入
  2. 建成一个堆(即符合堆特性的数组)
  3. 具体过程可以由上至下每个结点上滤,也可以由下至上(从非叶子结点开始)每个结点下滤,后者效率较高,详情见恋上数据结构二叉堆笔记
void BuildHeap(vector<int> &array)
{
   
    int index = array.size() / 2 -<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值