首页 > 编程语言 >【数据结构与算法】堆与堆排序

【数据结构与算法】堆与堆排序

时间:2023-03-20 22:33:56浏览次数:38  
标签:结点 int 堆排序 up down 算法 操作 数据结构 size

堆与堆排序

1 堆的概念

  • 用于维护一个数集。
  • 堆是一个完全二叉树
  • 小根堆:每个结点都小于等于它的左右子结点(递归定义)
    • 推论:每个结点都是以其为根节点的子树的最小值
image-20230311092859309
堆是一棵完全二叉树

2 堆的性质

  • 完全二叉树的性质:
image-20230311100905346
完全二叉树的性质
条件 编号(或数量)
完全二叉树的层数 \(\lceil\log_2n\rceil\)
完全二叉树根节点向下走到叶子结点的最大距离 \(\lfloor\log_2n\rfloor\)
最后一个非叶子结点(向下走到叶子结点最大距离为 1 的最后一个结点) n/2
向下走到叶子结点最大距离为 2 的最后一个结点 n/4
向下走到叶子结点最大距离为 d 的最后一个结点 \(n/2^d\)
向下走到叶子结点最大距离为 d 的结点个数 \(n/2^{d+1}-n/2^d=\)n/2^{d+1}$
  • 小根堆的性质:由小根堆的定义可得每个结点都是以其为根节点的子树的最小值

这也是堆排序的思想,每一次将小根堆的根节点输出,然后维护剩下的节点作为一个小根堆。

3 堆的实现(小根堆为例)

  • 使用一维数组来存储堆
    • 1 号点为根结点。
    • 结点 x 的左儿子是 2x ,右儿子是 2x+1
  • 堆的基本操作:
    • down(x) 操作,将结点往下移动来维护一个小根堆
      1. 结点 i 与其左右孩子 2i2i+1 比较,如果结点 i 不是三者之中的最小值,则结点 i 要向下移动。
      2. 结点 i 与其最小的孩子 t 交换位置后,然后递归 down(t)
    • up(x) 操作,把一个结点向上移动来维护一个小根堆
      1. 结点 i 与它的父节点 i/2 比较,如果父结点大于子结点,就将结点 ii/2 交换
      2. i /= 2 直到父结点小于子结点
image-20230320145826417
down 操作
/// down 操作
void down(int h[], int size, int i)
{
    int t = i;
    if(2 * i <= size && h[i] > h[2 * i]) t = 2 * i;
    if(2 * i + 1 <= size && h[t] > h[2 * i + 1]) t = 2 * i + 1;
    if(t != i)
    {
        int temp = h[i];
        h[i] = h[t];
        h[t] = temp;
        down(h, size, t);
    }
}
image-20230320182911841
up操作
/// up 操作
void up(int h[], int size, int i)
{
    while(i / 2 && h[i / 2] > h[i])
    {
        int temp = h[i];
        h[i] = h[i / 2];
        h[i / 2] = temp;
        i /= 2;
    }
}
  • 使用基本操作 updown 就可以完成如下操作:
/// - 插入操作
/// 新增元素插在末尾,然后对他进行 up 操作
heap[++ size] = x;up(size);

/// - 最小值
/// 根节点即为最小值
heap[1];

/// - 删除最小值
/// 用堆的最后一个元素覆盖根节点,然后堆的尺寸减 1
/// 然后对根节点执行 down 操作
heap[1] = heap[size];size--;
down(1);

/// - 删除任意一个元素
/// 用堆的最后一个元素覆盖要删除的元素,然后堆的尺寸减 1
/// 然后对覆盖后的结点执行 down 操作
heap[k] = heap[size];size--;
down(k);up(k);

/// - 修改一个元素的值
/// 修改结点元素值后,对其执行 down 操作或 up 操作
/// 这里减少了一个判断,down() 和 up() 都写上,只会执行其中一个。
heap[k] = x;down(x);up(x);

4 堆排序

  • 推排序用于对一维数组的元素进行排序
  1. down 操作将一维数组转换为小根堆
    • down 只对非叶子结点操作才有意义,由完全二叉树的性质,最后一个非叶子结点的编号为 n / 2
    • 因此,从 i = n/2i = 0 的结点进行 down 操作,这样就能得到小根堆
for(int i = size / 2; i; i--) down(i);
  1. 输出最小值,然后删除最小值,循环。
while(size)
{
    printf("%d ", h[1]);
    h[1] = h[size]; size--;
    down(1);
}
  • 堆排序实现
void heap_sort(int h[], int size)
{
    for(int i = size / 2; i; i--) down(i);
    
    while(size)
	{
        printf("%d ", h[1]);
        h[1] = h[size]; size--;
        down(h, size, 1);
	}
}
  • 堆排序时间复杂度:
    • i=n/2 开始每次 i-- 遍历,对每个结点执行 down(i) 操作
    • 最坏的情况下,由前面提到的完全二叉树的性质,n 个结点中有 \(n/2^{d+1}\) 个结点向下走到叶子结点最大距离为 d ,这些结点每个要执行 ddown 操作。因此总共的算法时间复杂度为:

\[T(n)=\sum_{d=1}^{\lfloor\log_2n\rfloor}\frac{n}{2^{d+1}}d \]

由上式,可推得(推导过程后面再补)堆排序算法复杂度为 \(O(1)\)

标签:结点,int,堆排序,up,down,算法,操作,数据结构,size
From: https://www.cnblogs.com/Critical-Thinking/p/17238204.html

相关文章

  • 算法笔记的笔记——第4章 算法初步
    排序选择排序(简单选择排序)从1到n进行n趟操作每趟从待排序部分(i到n)选择最小元素与待排序部分第一个元素(i)交换复杂度O(n2)for(inti=0;i<n;i++){ intk=i;......
  • [浅谈] 二维数据结构——树套树
    \(\color{purple}\text{Ⅰ.二维树状数组}\)\(\color{orange}\text{例一:P3372【模板】线段树1}\)$\color{green}\text{2023.1.1014:32}$回忆一下树状数组的区间修改......
  • 算法笔记的笔记——第5章 数学问题
    简单数学略最大公约数与最小公倍数最大公约数intgcd(inta,intb){if(b==0){returna;}else{returngcd(b,a%b);}}......
  • Boruvka 算法简记
    这个算法怕是只会存在于模拟赛里了。Boruvka算法是用于解决完全图的生成树的一类算法,因为完全图边数很多,因此普通时间复杂度基于边数的做法不适用。Boruvka算法核心思想......
  • [算法课]全面翻新计划!第二周全解
    文章目录​​上课内容​​​​试题A:组队​​​​数据​​​​详细分析​​​​颜老板版本暴力枚举​​​​吐槽​​​​更新版​​​​思路​​​​枚举版本​​​​思路......
  • [算法课]全面翻新计划!第十一周全解
    文章目录​​上课内容​​​​贪心法​​​​例1兑换货币​​​​颜老板代码​​​​更新版​​​​测试数据​​​​博主提示:​​​​注意:​​​​贪心算法的思路:​​​​......
  • 【Python】数据结构:字典,元素为键值对表示
    1.字典可以存储任意类型对象,每个元素由键值对组成。花括号scores={'张三':99,'李四':64,'王五':88}print(scores)#{'张三':99,'李四':64,'王五':88}pri......
  • 代码随想录算法训练营Day48 动态规划
    代码随想录算法训练营代码随想录算法训练营Day48动态规划|198.打家劫舍213.打家劫舍II337.打家劫舍III198.打家劫舍题目链接:198.打家劫舍你是一个专业的小偷,计划偷......
  • TZOJ 1222: 数据结构练习题――先序遍历二叉树 层次遍历
    描述 给定一颗二叉树,要求输出二叉树的深度以及先序遍历二叉树得到的序列。本题假设二叉树的结点数不超过1000。 输入 输入数据分为多组,第一行是测试数据的组数......
  • KMP算法
    KMP算法简介一种由Knuth(D.E.Knuth)、Morris(J.H.Morris)和Pratt(V.R.Pratt)三人设计的线性时间字符串匹配算法。该算法主要解决的就是字符串匹配的问题。本文参考前缀......