基本数据结构 —— 堆以及堆排序(C++实现)
什么是堆
堆(英语:heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
- 堆中某个节点的值总是不大于或不小于其父节点的值;
- 堆总是一棵完全二叉树。
通常将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的存储
堆一般使用数组存储。当堆中有n个元素的时,可以将这些元素存放在数组array的前n个单元里,其中堆的根节点中元素存放在array[1]中。结点之间的关系有两种情况:
- 如果根节点在数组中的位置是1,那么第i个位置的左右节点下标分别为2i、2i+1,父节点下标为i/2。
- 如果根节点在数组中的位置是0,那么第i个位置的左右节点下标分别为2i+1、2i+2,父节点下标为⌊(i-1) /2⌋。

堆的操作
以大根堆为例,给出堆支持的一些操作。
结构体定义
struct Heap
{
int size; // number of elements in array
int *array;
Heap() //init
{
size = 0;
array = new int[maxn];
}
Heap(int n) //init
{
size = 0;
array = new int[n];
}
~Heap() //free memory
{
delete array;
}
};
判断是否为空
bool empty()
{
if(size != 0) return false;
return true;
}
往堆中插入元素
void insert(int value)
{
array[++size] = value; // 数组的最末尾插入新节点
int index = size;
while(index > 1) // 自下而上地调整子节点与父节点的位置
{
// 如果大于父节点的值,根据最大堆的特点,子节点上升,而父节点要下降
if(array[index] > array[index/2]) swap(array[index],array[index/2]);
index /= 2; // 继续向上搜索
}
}

从堆中删除元素
void del()
{
if(empty()) return; // 删除前不能为空
swap(array[1],array[size--]); //用数组最末尾节点覆盖被删节点
int index = 1;
while(2*index <= size) // 从上到下调整二叉堆
{
int next = 2*index;
// 选取子节点中最大的
if(next < size && array[next+1] > array[next]) next++;
// 与子节点中最大的比较,如果小于则当前结点下降
if(array[index] < array[next])
{
swap(array[index],array[next]);
index = next;
}
else break;
}
}

取出堆中最大的元素
int max() {
if(empty()) return -1;
return array[1];
}
堆排序
给定一个有size个元素的数组array,可用下面的算法buildHeap(array,size)在 O(n) 时间内将数组array调整为一个堆。
void buildHeap(int array[],int size)
{
int i,tmp,index;
for(i = size/2; i >= 1; i--)
{
tmp = array[i];
index = 2*i;
while(index <= size)
{
if(index < size && array[index+1] > array[index]) index++;
if(array[index] < tmp) break;
array[index/2] = array[index];
index *= 2;
}
array[index/2] = tmp;
}
}
测试代码
#include<iostream>
#include<algorithm>
#define maxn 1001 //heap's size
using namespace std;
struct Heap {
int size; // number of elements in array
int *array;
Heap() { //init
size = 0;
array = new int[maxn];
}
Heap(int n) { //init
size = 0;
array = new int[n];
}
~Heap() { //free memory
delete array;
}
bool empty() {
if(size != 0) return false;
return true;
}
void insert(int value) {
array[++size] = value;
int index = size;
while(index > 1) {
if(array[index] > array[index/2]) swap(array[index],array[index/2]);
index /= 2;
}
}
void del()
{
if(empty()) return;
swap(array[1],array[size--]);
int index = 1;
while(2*index <= size)
{
int next = 2*index;
if(next < size && array[next+1] > array[next]) next++;
if(array[index] < array[next])
{
swap(array[index],array[next]);
index = next;
} else break;
}
}
int max() {
if(empty()) return -1;
return array[1];
}
};
void buildHeap(int array[],int size) {
int i,tmp,index;
for(i = size/2; i >= 1; i--) {
tmp = array[i];
index = 2*i;
while(index <= size) {
if(index < size && array[index+1] > array[index]) index++;
if(array[index] < tmp) break;
array[index/2] = array[index];
index *= 2;
}
array[index/2] = tmp;
}
}
int main() {
int n,i,j,k;
cout << "input heap's size:";
cin >> n;
Heap H = Heap(n);
int* array = new int[n];
for(i = 1; i <= n; i++) {
int tmp;
cin >> tmp;
array[i] = tmp;
H.insert(tmp);
}
buildHeap(array,n);
for(i = 1; i <= n; i++) {
cout << array[i] << " ";
}
cout << endl;
while(!H.empty()) {
cout << H.max() << endl;
H.del();
}
return 0;
};
结果:

例题
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
class Solution {
public:
struct Heap {
int size; // number of elements in array
int *array;
Heap() { //init
size = 0;
array = new int[1001];
}
Heap(int n) { //init
size = 0;
array = new int[n];
}
~Heap() { //free memory
delete array;
}
bool empty() {
if(size != 0) return false;
return true;
}
void insert(int value) {
array[++size] = value;
int index = size;
while(index > 1) {
if(array[index] < array[index/2]) swap(array[index],array[index/2]);
index /= 2;
}
}
void del()
{
if(empty()) return;
swap(array[1],array[size--]);
int index = 1;
while(2*index <= size)
{
int next = 2*index;
if(next < size && array[next+1] < array[next]) next++;
if(array[index] > array[next])
{
swap(array[index],array[next]);
index = next;
} else break;
}
}
int min() {
if(empty()) return -1;
return array[1];
}
};
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> ret;
int i,n = input.size();
if(n < k) return ret;
Heap H = Heap(n);
for(i = 0;i < n;i++)
{
H.insert(input[i]);
}
while(k)
{
ret.push_back(H.min());
H.del();
k--;
}
return ret;
}
};
参考资料
- 数据结构图文解析之:二叉堆详解及C++模板实现
- 《数据结构(C语言描述)(修订版)》电子工业出版社
基本数据结构 —— 堆以及堆排序(C++实现)的更多相关文章
- 基本数据结构——堆(Heap)的基本概念及其操作
基本数据结构――堆的基本概念及其操作 小广告:福建安溪一中在线评测系统 Online Judge 在我刚听到堆这个名词的时候,我认为它是一堆东西的集合... 但其实吧它是利用完全二叉树的结构来维护一组 ...
- C 数据结构堆
引言 - 数据结构堆 堆结构都很耳熟, 从堆排序到优先级队列, 我们总会看见它的身影. 相关的资料太多了, 堆 - https://zh.wikipedia.org/wiki/%E5%A0%86%E7 ...
- java数据结构----堆
1.堆:堆是一种树,由它实现的优先级队列的插入和删除的时间复杂度都是O(logn),用堆实现的优先级队列虽然和数组实现相比较删除慢了些,但插入的时间快的多了.当速度很重要且有很多插入操作时,可以选择堆 ...
- python下实现二叉堆以及堆排序
python下实现二叉堆以及堆排序 堆是一种特殊的树形结构, 堆中的数据存储满足一定的堆序.堆排序是一种选择排序, 其算法复杂度, 时间复杂度相对于其他的排序算法都有很大的优势. 堆分为大头堆和小头堆 ...
- 数据结构-堆 Java实现
数据结构-堆 Java实现. 实现堆自动增长 /** * 数据结构-堆. 自动增长 * */ public class Heap<T extends Comparable> { priva ...
- 数据结构 - 堆(Heap)
数据结构 - 堆(Heap) 1.堆的定义 堆的形式满足完全二叉树的定义: 若 i < ceil(n/2) ,则节点i为分支节点,否则为叶子节点 叶子节点只可能在最大的两层出现,而最大层次上的叶 ...
- [数据结构]——堆(Heap)、堆排序和TopK
堆(heap),是一种特殊的数据结构.之所以特殊,因为堆的形象化是一个棵完全二叉树,并且满足任意节点始终不大于(或者不小于)左右子节点(有别于二叉搜索树Binary Search Tree).其中,前 ...
- JAVA数据结构(十一)—— 堆及堆排序
堆 堆基本介绍 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,最坏,最好,平均时间复杂度都是O(nlogn),不稳定的排序 堆是具有以下性质的完全二叉树:每个节点的值都大于或等 ...
- 数据结构-堆(应用篇)之堆排序法-C和C++的实现
堆排序 关于堆的内容我们已经在上一节中了解了,本节中将给出一个堆的应用-堆排序. 关于堆的概念可以看上一节,入口:http://www.cnblogs.com/HongYi-Liang/p/78536 ...
随机推荐
- 最近遇到的几个问题,关于Unity脚本在Inspector视图中前面没有勾选框的问题
1.为什么在Inspector视图中有的脚本前面有勾选框,有的脚本前面没有? 当我想要禁用一个脚本时,发现脚本前面没有勾选框,有的却有. 解决办法:在脚本中添加start方法,然后就有勾选框了. 原因 ...
- python3 拼接字符串的7种方法
1.直接通过(+)操作符拼接 1 2 >>> 'Hello' + ' ' + 'World' + '!' 'Hello World!' 使用这种方式进行字符串连接的操作效率低下,因为 ...
- C++判断回文
判断一个字符串是否为回文,如“goddog”. 代码: #include <iostream> #include <string> #include <stdio.h&g ...
- 时间戳使用的bug,你见过么
博主本人前几天给公司项目里写了个禁言和解除禁言的功能,项目中涉及到对时间的处理,因为学得时候也没很注意,就按自己的思路去写了,运行起来发现了一个天大的bug,就是写的延后一年尽然,刚开始就执行了,而且 ...
- sync命令详解
转:https://blog.csdn.net/everything1209/article/details/50423679 1.谁和谁同步? 2.为什么要同步?复制移动的过程不是同步的吗,都发生了 ...
- ./configure的含义
在实践安装nginx的时候,不知道./configure是什么意思,这里特地记录一下. 在linux中./代表当前目录,属于相对路径../代表上一级目录,属于相对路径/代表根目录,/开头的文件都是绝对 ...
- PSP总结
一.回顾1 (1)回想一下你曾经对计算机专业的畅想 当初你是如何做出选择计算机专业的决定的?经过一个学期,你的看法改变了么,为什么? 以前的回答:当初之所以选择计算机专业,是因为我比较喜欢数学,觉得计 ...
- 课堂实践ASL博客
实践博客 二分法查找元素 1.首先定义三个位置min,mid,max 2.每次从所有元素所处位置的中间开始查找(所有元素必须以由小及大顺序排列完毕) 3.当中间元素大于所查找元素时,从中间元素(mid ...
- 手机端学习助手的说明书需求以及团队PM选择
1.产品的背景 课堂上知识容量大.密度高,学生不能立刻掌握所学知识点,同时,网上资料冗杂繁复,指向性不强,导致学生不能高效的学习,为了充分利用学生的课余时间,培养学生自学能力,辅助老师教学,我们小组希 ...
- BATA冲刺准备
目录 第一部分 调研,评测 福大助手的bug IOS端 Android端 福大助手结构体系的思维导图 为什么开发人员没有发现这个bug 假设团队开发这款app,应注意哪些方面(架构.部署运维.微服务等 ...