什么是堆

堆(英语: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. c语言数字图像处理(十):阈值处理

    定义 全局阈值处理 假设某一副灰度图有如下的直方图,该图像由暗色背景下的较亮物体组成,从背景中提取这一物体时,将阈值T作为分割点,分割后的图像g(x, y)由下述公式给出,称为全局阈值处理 多阈值处理 ...

  2. 模块化开发之butterknife 在 library中使用

    在Android开发中butterknife是一个很好的对资源初始化的工具,它可以使你的代码简洁通俗易懂,同时配合Android ButterKnife Zelezny插件可以让你写代码的速度提升至少 ...

  3. 通过python将xml文件转换成html文件

    #数据类型的转换 def main():    maxwidth = 100  #用于规范字段的长度    print_start()    count=0    while True:        ...

  4. web小结

    一.ajax 1.用于前端向服务器异步获取数据 json数组:可以直接通过数组下标获取到值 json对象:可以用“data.xx”获取到值 2.注意事项 同时请求两个ajax时,容易出现异常,第一个a ...

  5. linux一切皆文件之文件描述符(一)

    一.知识准备 1.在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件.如:普通文件.目录.字符设备.块设备.套接字等 2.当一个文件被进程打开,就会创建一个文件描述符.这时候,文件的路径就 ...

  6. NuGet 让程序集版本变得混乱

    之前引用的 System.Net.Http.Formatting ,是依赖于   System.Net.Http 2.0的. 更新引用后它是依赖于  System.Net.Http 4.0 的.而且一 ...

  7. 局域网传输-LED灯搭建局域网:数据传输可达每秒3Gb

    一 : LED灯搭建局域网:数据传输可达每秒3Gb 我们之前介绍了利用可见光通讯技术,通过LED灯光实现精准室内定位的例子.实际上,这种灯泡和技术的用途不止于此,比如,它还能进行无线网络传输. 最近, ...

  8. java第一次实验报告

    北京电子科技学院(BESTI) 实    验    报    告 课程名称:java实验      班级:1352         姓名:潘恒      学号:20135209 成绩:         ...

  9. visual stdio2013软件安装及单元测试

    visual stdio2013软件安装及单元测试 一.visual stdio2013软件安装详解 今天,笔者为大家带来如何在Windows10下完美安装Visual Studio 2013专业版. ...

  10. 将url的参数解析为Json数据

    代码如下: <!DOCTYPE> <html lang="en"> <head> </head> <body> < ...