随便说说堆(一)——二叉堆

二叉堆可以被看作是一个数组,也可以简单的看作是一个近似的完全二叉树,二叉堆有最大堆和最小堆,分别具有堆的性质:最大堆的某个结点的值最多与其父结点一样大,最小堆则是某个结点的值最多与其父结点一样小。所以最大堆中最大的结点永远是根结点,最小堆中最小的结点永远是根节点。

既然二叉堆是一种数据结构,就有其支持的操作(这里以最小堆为例):

  • make_heap:建立一个空堆,或者把数组中元素转换成二叉堆。
  • insert:插入元素。
  • minimun:返回一个最小数。
  • extract_min:移除最小结点。
  • union:合并堆

make_heap

先给一组数{27,17,3,16,13,10,1,5,7}输入数组,数组下标从0开始。然后我们画出这棵树:

然后根据近似满二叉树的性质,有n个结点,[n/2]+1,[n/2]+2,……,n都是叶结点。然后可以通过对除了叶结点以外的结点i(0到n/2)进行一次下滤的操作,若儿子结点有小于结点i的结点,将儿子结点中最小者与结点i交换,再与交换后的位置的儿子结点继续比较,直到小于儿子结点或者为叶结点为止。遍历完,就得到最小堆。 时间复杂度建立空堆O(1),立地建堆O(n)。

图示

代码实现

 1 //维护堆
 2 void max_heapify(int *a, int i) {
 3     int l = 2 * i + 1;
 4     int r = 2 * i + 2;
 5     int largest;
 6     if (a[l] != -1 && a[l] < a[i]) largest = l;
 7     else largest = i;
 8     if (a[r] != -1 && a[r] < a[largest]) largest = r;
 9     if (largest != i) {
10         swap(a[i], a[largest]);
11         max_heapify(a, largest);
12     }
13 }
14 //建堆
15 void make_heap(int *a, int n) {
16     for (int i = n / 2; i >= 0; i--) max_heapify(a, i);
17 }

insert

对于插入操作,首先将元素push到数组尾部,然后将其进行上滤操作,也就是将其与父结点比较,如果小于父结点就交换,直到大于等于父结点或者到达根。时间复杂度为O(logn)

举个例子:在{1,5,3,7,13,10,27,16,17}中插入4。

图示

代码实现

1 //n是数组长度
2 void insert(int *a, int num, int &n) {
3     a[n++] = num;
4     for (int i = n - 1; i >= 0; i = (i - 1) / 2) {
5         if (a[i] < a[(i - 1) / 2]) swap(a[i], a[(i - 1) / 2]);
6         else break;
7     }
8 }

minimun

返回最小数,对于最小堆来说返回根即可。时间复杂度O(1)

代码实现

1 int minimun(int *a) {
2     return a[0];
3 }

extract_min

移除最小顶点,也就是最小堆的根,此时需要将堆最后一个叶节点摘下替换掉根,这样不会破坏近似满二叉树的结构,然后从上至下更新堆,维护堆的性质。时间复杂度O(logn)

图示

代码实现

1 void extract_min(int *a, int &n) {
2     a[0] = a[n - 1];
3     n--;
4     max_heapify(a, 0);
5 }

union

合并堆的话其实就相当于把两个堆数组合并,然后重新建堆。所以时间复杂度也是线性的,为O(n)。

代码实现

1 void Union(int *a, int *b, int &n, int &m) {
2     for (int i = 0; i < m; i++) {
3         a[n++] = b[i];
4     }
5     m = 0;
6     memset(b, -1, sizeof(b));
7     for (int i = n / 2; i >= 0; i--) max_heapify(a, i);
8 }

这里就说完了二叉堆,下一篇在随便说说堆中的二项堆。

原文地址:https://www.cnblogs.com/pullself/p/10161645.html

时间: 2024-08-03 20:56:55

随便说说堆(一)——二叉堆的相关文章

堆、二叉堆、堆排序

堆.二叉堆.堆排序 堆的概念: n个元素序列 { k1, k2, k3, k4, k5, k6 -. kn } 当且仅当满足以下关系时才会被称为堆: ki <= k2i,ki <= k2i+1 或者 ki >= k2i,ki >= k2i+1 (i = 1,2,3,4 .. n/2) 如果数组的下表是从0开始,那么需要满足 ki <= k2i+1,ki <= k2i+2 或者 ki >= k2i+1,ki >= k2i+2 (i = 0,1,2,3 .. n

堆之二叉堆

堆的定义 堆通常是一个可以被看做一棵树,它满足下列性质: 堆中任意节点的值总是不大于(不小于)其子节点的值: 堆总是一棵完全树. 将任意节点不大于其子节点的堆叫做最小堆或小根堆,而将任意节点不小于其子节点的堆叫做最大堆或大根堆.常见的堆有二叉堆.左倾堆.斜堆.二项堆.斐波那契堆等等. 二叉堆 堆有两种性质:结构性和堆序性 结构性:堆是一颗完全二叉树.若设完全二叉树的高度是h,则它的节点数是2^h到2^(h+1) - 1:则节点数为N的完全二叉树的高度O(logn). 完全二叉树中父子节点位置关系

在A*寻路中使用二叉堆

接上篇:A*寻路初探 GameDev.net 在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序:     这一篇文章,是"A* Pathfinding for Beginners.",也就是我翻译的另一篇文章<A*寻路初探>的补充,在这篇文章里,作者再一次展现了他阐述复杂话题的非凡能力,用通俗易懂的语句清晰的解释了容易让人迷惑的问题.还是那句话,如果你看了这篇文章仍然无法领会作者的意图,那

映射二叉堆

定义 具有映射功能的堆称为双向映射堆.堆又名二叉堆,所以也常常称其为映射二叉堆. 映射二叉堆相比普通的堆,核心功能是支持元素的快速查找,可以在O(logn) 的时间复杂度内找到索引为 id 的元素 (没有重复索引,索引并非堆中用来比较大小的关键字),并进行后续的修改或删除等操作. 映射二叉堆与普通堆的不同之处是它不存储数值,而是存储数据对应的索引. 当需要比较父子结点的大小时,我们需要对两个索引对应的关键字进行比较:当需要交换父子结点时,我们要交换堆中父子结点的索引. 在堆的外部还需要存储一个从

【数据结构】二叉堆

看到一篇很好的博文,来自http://blog.csdn.net/morewindows/article/details/6709644 下面是博文内容 堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法.学习堆排序前,先讲解下什么是数据结构中的二叉堆. 二叉堆的定义 二叉堆是完全二叉树或者是近似完全二叉树. 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值. 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆).

PHP利用二叉堆实现TopK-算法的方法详解

前言 在以往工作或者面试的时候常会碰到一个问题,如何实现海量TopN,就是在一个非常大的结果集里面快速找到最大的前10或前100个数,同时要保证 内存和速度的效率,我们可能第一个想法就是利用排序,然后截取前10或前100,而排序对于量不是特别大的时候没有任何问题,但只要量特别大是根本不可能 完成这个任务的,比如在一个数组或者文本文件里有几亿个数,这样是根本无法全部读入内存的,所以利用排序解决这个问题并不是最好的,所以我们这里就用 php去实现一个小顶堆来解决这个问题. 二叉堆 二叉堆是一种特殊的

普林斯顿公开课 算法4-2:二叉堆

二叉树 介绍二叉堆之前首先介绍二叉树.二叉树有一个根节点,节点下又有两个子节点.完全二叉树是指一个二叉树树除了最底层,其他层都是完全平衡的. 完全二叉树最基本的性质就是它的高度是 floor(lgN). 二叉堆 二叉堆是完全二叉树的一种,每个节点对应一个数值,而且这个数值都大于等于它子节点的数值. 下图是一个二叉堆. 二叉堆的储存 由于二叉堆是完全二叉树,所以它可以用一个数组进行储存.所以不需要创建节点对象,再建立节点之间的连接.这样节省了很多开销. 用数组a[]表示一个二叉堆有以下特性: a[

《Algorithms算法》笔记:优先队列(2)——二叉堆

二叉堆 1 二叉堆的定义 堆是一个完全二叉树结构(除了最底下一层,其他层全是完全平衡的),如果每个结点都大于它的两个孩子,那么这个堆是有序的. 二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组中按照层级存储(不用数组的第一个位置) 2 二叉堆的性质 最大的元素在a[1] (root结点) 每个k的父亲在k/2 每个k的孩子在k*2和k*2+1 3 二叉堆的操作 3.1 上浮(孩子大于父亲)--对应插入操作 循环,每次比较自己和父亲,如果比父亲大就交换,直到root. 3.2 插入 先把元

二叉堆 及 大根堆的python实现

Python 二叉堆(binary heap) 二叉堆是一种特殊的堆,二叉堆是完全二叉树或者是近似完全二叉树.二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆. 当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆. 当父节点的键值总是小于或等于任何一个子节点的键值时为最小堆. 二叉堆的存储 二叉堆一般用数组来表示.如果根节点在数组中的位置是1,第n个位置的子节点分别在2n和 2n+1.因此,第1个位置的子节点在2和3,第2

【qbxt!预习】二叉堆

qxbt的老师发消息来说让自己预习,本来想中考完之后认真学(颓)习(废)  没办法 0. 数据结构图文解析系列 1. 二叉堆的定义 二叉堆是一种特殊的堆,二叉堆是完全二叉树或近似完全二叉树.二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆.当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆. 当父节点的键值总是小于或等于任何一个子节点的键值时为最小堆. 2. 二叉堆的存储 二叉堆一般使用数组来表示.请回忆一下二叉树的性质,