什么是堆

堆(英语: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;
};

结果:

例题

最小的K个数 —— 剑指offer

输入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++实现)的更多相关文章

  1. 基本数据结构——堆(Heap)的基本概念及其操作

    基本数据结构――堆的基本概念及其操作 小广告:福建安溪一中在线评测系统 Online Judge 在我刚听到堆这个名词的时候,我认为它是一堆东西的集合... 但其实吧它是利用完全二叉树的结构来维护一组 ...

  2. C 数据结构堆

    引言 - 数据结构堆 堆结构都很耳熟, 从堆排序到优先级队列, 我们总会看见它的身影. 相关的资料太多了, 堆 - https://zh.wikipedia.org/wiki/%E5%A0%86%E7 ...

  3. java数据结构----堆

    1.堆:堆是一种树,由它实现的优先级队列的插入和删除的时间复杂度都是O(logn),用堆实现的优先级队列虽然和数组实现相比较删除慢了些,但插入的时间快的多了.当速度很重要且有很多插入操作时,可以选择堆 ...

  4. python下实现二叉堆以及堆排序

    python下实现二叉堆以及堆排序 堆是一种特殊的树形结构, 堆中的数据存储满足一定的堆序.堆排序是一种选择排序, 其算法复杂度, 时间复杂度相对于其他的排序算法都有很大的优势. 堆分为大头堆和小头堆 ...

  5. 数据结构-堆 Java实现

    数据结构-堆 Java实现. 实现堆自动增长 /** * 数据结构-堆. 自动增长 * */ public class Heap<T extends Comparable> { priva ...

  6. 数据结构 - 堆(Heap)

    数据结构 - 堆(Heap) 1.堆的定义 堆的形式满足完全二叉树的定义: 若 i < ceil(n/2) ,则节点i为分支节点,否则为叶子节点 叶子节点只可能在最大的两层出现,而最大层次上的叶 ...

  7. [数据结构]——堆(Heap)、堆排序和TopK

    堆(heap),是一种特殊的数据结构.之所以特殊,因为堆的形象化是一个棵完全二叉树,并且满足任意节点始终不大于(或者不小于)左右子节点(有别于二叉搜索树Binary Search Tree).其中,前 ...

  8. JAVA数据结构(十一)—— 堆及堆排序

    堆 堆基本介绍 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,最坏,最好,平均时间复杂度都是O(nlogn),不稳定的排序 堆是具有以下性质的完全二叉树:每个节点的值都大于或等 ...

  9. 数据结构-堆(应用篇)之堆排序法-C和C++的实现

    堆排序 关于堆的内容我们已经在上一节中了解了,本节中将给出一个堆的应用-堆排序. 关于堆的概念可以看上一节,入口:http://www.cnblogs.com/HongYi-Liang/p/78536 ...

随机推荐

  1. 0.0 配置JAVA环境和Maven环境(W10注意点)

    今天上班第一天,真有些忘了之前配置的环境问题,全新的电脑开始配置. 电脑软件JDK以及eclipse都是下载最新的 添加最全的链接吧: 1.JDK配置链接:http://www.cnblogs.com ...

  2. linux上的mysql配置过程

    自己阿里云上的服务器,记录下mysql的配置过程防止后面忘记 1. 首先用apt-get工具安装mysql sudo apt-get install mysql-server sudo apt-get ...

  3. Docker容器的启动与停止

    启动docker:systemctl start docker 停止docker:systemctl stop docker 重启docker:systemctl restart docker 查看d ...

  4. Navicat连接mysql报错1251

    Navicat无法连接MySQL8,是因为MySQL8的方式和MySQL5的加密方式不一样导致 解决方案: 1.通过命令行进入mysql数据库: C:\Windows\system32> mys ...

  5. 你也可以手绘二维码(二)纠错码字算法:数论基础及伽罗瓦域GF(2^8)

    摘要:本文讲解二维码纠错码字生成使用到的数学数论基础知识,伽罗瓦域(Galois Field)GF(2^8),这是手绘二维码填格子理论基础,不想深究可以直接跳过.同时数论基础也是 Hash 算法,RS ...

  6. 团队博客作业Week2 --- 学长学姐访谈录

    ## 团队作业2 ## ### 团队一 ### 这个团队中组员是位研一的学姐,她的软件工程老师是姚淑珍,当时她们团队总共有4个人,而且她们都很努力,但是可能是最后团队的作品不太理想,她们的软件并没有上 ...

  7. 第三次博客作业JSF

    JSF规格化设计发展史以及为什么得到人们重视 查阅了n多资料但是仍然没找到. 就说一些jsf的优势吧. 优势:    (1)UI组件 (2)事件驱动模式 (3)用户界面到业务逻辑的直接映射 (4)程序 ...

  8. beta冲刺7/7

    队名:Boy Next Door 燃尽图 代码写入 https://github.com/mangoqiqi/paybook/tree/master/Desktop/Web%E8%B4%A6%E5%8 ...

  9. Head First Java & final

  10. JavaBean 与 EJB 的区别

    JavaBean在一般情况下指的是实体类,在大部分情况下和POJO是同义词,基本构成就是一些字段和与之对应的 setter.getter方法,如果一个JavaBean需要在不同的JVM的进程中进行传递 ...