大顶堆、小顶堆

2024-02-21 00:28
文章标签 大顶 小顶

本文主要是介绍大顶堆、小顶堆,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    • 堆的维护
      • 1.自我初始化
      • 代码
      • 2.插入时维护
      • 时间复杂度

代码如有误欢迎指出

本文是最近在整理排序算法的时候写到堆排序单拎出来写的,目前只有维护代码

堆是一颗完全二叉树,同时保证所有双亲都比自己的孩子大(可以相等

堆的维护

使用数组存储,长度为 n+1,从 1 索引开始存储,对 i i i 2 i 2i 2i 2 i + 1 2i+1 2i+1 是孩子, i 2 \frac{i}{2} 2i是双亲

1.自我初始化

把一个现有数组自我初始化为堆:
 原理:
先把小的子树维护好,然后由小至大维护
从第二小的子树开始(最小的子树是叶子)
找到子树,维护就是看左右子树是否有应该当堆顶的(如小顶堆就是找是否有比双亲节点小的孩子)

 实现:
索引值最大的第二小的子树是几?是 n 2 \frac{n}{2} 2n
注意,调整子树的堆顶之后有可能影响子树的子树,需要往下继续维护,直到叶子

维护小顶堆示例:
在这里插入图片描述
在这里插入图片描述

代码

/*测试样例1
8 
53 17 72 5 39 67 94 25
得到:
5 17 67 25 39 72 94 53
*/
/*测试样例2
9 
53 17 72 5 39 94 67 25 1
得到:
1 5 67 17 39 94 72 25 53
*/
#include <iostream>
using namespace std;
int nums[105];
int n;void adjustDown(int heap[],int i,int n)
{int child_p = 2 * i;    //i结点(在循环中是指对应调整的子树)的孩子的索引int parent = heap[i];   //本子树的根结点的值while (child_p<=n)      //保证双亲是有孩子结点的,叶子结点本身就是排好的堆,不需要调整{if (child_p + 1 <= n && heap[child_p + 1] < heap[child_p])   child_p++;//选中左右孩子中更小的和双亲作比较if (heap[child_p] < parent){heap[child_p / 2] = heap[child_p];//将孩子的值赋给父亲child_p *= 2;}else{break;}}heap[child_p/2] = parent;//这一步容易忘记!!!!就是赋回i结点的值!当然如果每次比较完用tmp去做交换就可以不用这么麻烦,我就是不想用tmp交换,因为那样有三次赋值,而这样写只有一次
}int main()
{//数组初始化cin >> n;for (int i = 1; i <= n; i++){cin >> nums[i];}//小顶堆初始化for (int i = n/2; i >=1; i--){adjustDown(nums, i, n);}//排序后展示for (int i = 1; i <= n; i++){cout << nums[i] << ' ';}cout << endl;
}

2.插入时维护

思路和自我初始化差不多,就是从下而上,从插入结点的双亲比较,往上找需要调整的每一个结点

/*测试样例1
8
53 17 72 5 39 67 94 25
得到:
5 17 67 25 39 72 94 53
*/
/*测试样例2
9
53 17 72 5 39 94 67 25 1
得到:
1 5 67 17 39 94 72 53 25(注意,这个和自我初始化的结果不一定一样)
*/
#include <iostream>
using namespace std;
int nums[105];
int n;void heapInsertAdjust(int heap[], int i)//尾部插入后做的调整
{int child = heap[i];    //最初插入的值,循环中做每次比较的孩子int parent_p = i / 2;   //循环中每次比较的双亲索引int lastParent_p = i;   //循环中最后一次赋给双亲的位置,默认不交换就是i原地(其实就是“上一个双亲”的位置,因为/2会默认向下取整,需要用这个标记while (parent_p >= 1){if (heap[parent_p] > child){heap[lastParent_p] = heap[parent_p];  //将双亲的值赋给孩子,继续往上找lastParent_p = parent_p;              //更新赋值位置parent_p /= 2;}else break;}heap[lastParent_p] = child;
}int main()
{//数组初始化cin >> n;for (int i = 1; i <= n; i++){int tmp;cin >> nums[i];heapInsertAdjust(nums, i);//插入的时候调整}//排序后展示for (int i = 1; i <= n; i++){cout << nums[i] << ' ';}cout << endl;
}

时间复杂度

插入时维护:O(logn)
自我初始化:adjustDown部分为O(logn),有n/2趟,所以是O(nlogn)

这篇关于大顶堆、小顶堆的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/730028

相关文章

【Java 优先队列(小顶堆) 分治法 实现合并k个排序链表】

合并k个排序链表 题目:力扣-合并k个排序链表[https://leetcode.cn/problems/vvXgSW/](https://leetcode.cn/problems/vvXgSW/)优先队列(小顶堆)法代码实现 分治法代码实现 题目:力扣-合并k个排序链表https://leetcode.cn/problems/vvXgSW/ 给定一个链表数组,每个链表都已经

【C++】大顶堆(最大堆)手工模拟优先队列

前言 本文采用结构体重载比较运算符的方式进行大根堆的建立,算法逻辑类似 S T L STL STL的 p r i o r i t y _ q u e u e priority\_queue priority_queue。 结构体 堆本身就是一颗完全二叉树,所以本身用数组存储就行。 int heap[N]; 输入堆 for(int i=1;i<=n;i++} cin>>heap[i];

堆:什么是大顶堆,什么是小顶堆,堆排序,代码实现堆排序

堆排序代码 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace 堆排序___顺序存储{class Program{static void Main(string[] arg

wikioi 2573 大顶堆与小顶堆并用

题目描述 Description 我们使用黑匣子的一个简单模型。它能存放一个整数序列和一个特别的变量i。在初始时刻,黑匣子为空且i等于0。这个黑匣子能执行一系列的命令。有两类命令: ADD(x):把元素x放入黑匣子;GET:把i加1的同时,输出黑匣子内所有整数中第i小的数。牢记第i小的数是当黑匣子中的元素已非降序排序后位于第i位的元素。 下面的表6_4是一个11个命令的例子:

wikioi 1245 小顶堆

题目描述 Description 有两个长度为 N 的序列 A 和 B,在 A 和 B 中各任取一个数可以得到 N^2 个和,求这N^2 个和中最小的 N个。 输入描述 Input Description 第一行输入一个正整数N;第二行N个整数Ai 且Ai≤10^9;第三行N个整数Bi, 且Bi≤10^9 输出描述 Output Descriptio

wikioi 1052 大顶堆

题目描述 Description     王钢是一名学习成绩优异的学生,在平时的学习中,他总能利用一切时间认真高效地学习,他不但学习刻苦,而且善于经常总结、完善自己的学习方法,所以他总能在每次考试中得到优异的分数,这一切很大程度上是由于他是一个追求效率的人。     但王钢也是一个喜欢玩的人,平时在学校学习他努力克制自己玩,可在星期天他却会抽一定的时间让自己玩一下,他的爸爸妈妈

牛客NC392 参加会议的最大数目【中等 贪心+小顶堆 Java/Go/PHP 力扣1353】

题目 题目链接: https://www.nowcoder.com/practice/4d3151698e33454f98bce1284e553651 https://leetcode.cn/problems/maximum-number-of-events-that-can-be-attended/description/ 思路 贪心+优先级队列 Java代码 import

C++小顶堆求Topk

C++小顶堆求Topk 求数组中的Topk数字,比如【1、4、6、7、2、9、8、3、5、0】的Top4是【6、7、8、9】。 用小顶堆来实现, 首先用前4个元素新建一个大小为4的小顶堆,堆顶始终保存堆中的最小值。数组中的剩余数字是【2、9、8、3、5、0】然后逐个将剩余数字与堆顶比较,如果大于堆顶,则与堆顶交换,并向下调整堆。最后堆中保存的就是最大的4个数字。 代码如下,MinHeap.

数据结构 小顶堆建堆过程 构建过程

【一】简介 最小堆是一棵完全二叉树,非叶子结点的值不大于左孩子和右孩子的值。本文以图解的方式,说明最小堆的构建、插入、删除的过程。搞懂最小堆的相应知识后,最大堆与此类似。最小堆示例:   【二】最小堆的操作 最小堆的构建:       初始数组为:9,3,7,6,5,1,10,2       按照完全二叉树,将数字依次填入。       填入完成后,从最后一个非叶子结点(本示例为数

【Python】 小顶堆:困难 Leetcode 23. 合并 K 个升序链表 -- Python中heapq对于自定义数据类型的比较

描述 给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。 示例 1: 输入:lists = [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 代码 代码1 由于可能存在相同值的结点,当用元组或数组作为堆中元素时,会出现无法比较结点的情况。在这里解决的方法是每个元组中再添加进一个独一无二的id cl