⑥二叉堆

定义:

二叉堆是一颗被完全填满的二叉树,底层是从左到右填入。即完全二叉树。一棵高为h的完全二叉树有2^h到2^(h+1)-1个节点。这个还是很好证明的。由于完全二叉树很有规律,所以我们用数组而不是指针来表示它。

 对于任意位置i上的元素,左儿子位置为2i,右儿子(2i+1),父亲为[i/2](向下取整)

 1 typedef struct HeapStruct *PriorityQueue;
 2 #define Mindata -10000
 3 struct HeapStruct{
 4     int *Element;//成员数组
 5     int Capacity;//容量
 6     int Size;//当前大小
 7 };
 8
 9 PriorityQueue Initial(int MaxElements){
10     PriorityQueue H;
11     H = (PriorityQueue)malloc(sizeof(struct HeapStruct));
12     H->Capacity = MaxElements;
13     H->Size = 0;
14     H->Element = (int*)malloc(sizeof(int)*(MaxElements + 1));
15     H->Element[0] = Mindata;
16     return H;
17 }

这里这个Mindata还是很有讲究的,后面解释。

堆可以分成最小堆和最大堆。

最小堆:对于每个节点X,X的父亲中的关键字小于或等于X。也就是对任意一棵树(子树),根节点总是最小的。

插入:

eg:插入14 

    

最初插入的位置是16的左节点,然后与16比,发现14比16小,那就违反了最小堆原则。那就把16放到14的位置,14上移动。

然后再和13比,发现已经比小了,那就符合最小堆条件,不需要再移动,所以插入完成。

 1 void Insert(int X, PriorityQueue H){
 2     int i = 0;
 3     if (H->Size == H->Capacity){
 4         printf("full!");
 5     }
 6     else{
 7         for (i = ++H->Size; X < H->Element[i / 2]; i /= 2)
 8             H->Element[i] = H->Element[i / 2];
 9         H->Element[i] = X;
10     }
11 }

这里就显示出MinData的好处了。 如果你现在要插入的是11,那么就比13这个原来的根节点还要小。但这时候根节点已经没有父节点的,而[1/2]=0, Element[0]又是你自己定义的最小的一个元素,所以11就直接留在根那块停下来了。当然不用Mindata做个判断语句当然也是可行的。

这里有用到一个策略叫做‘‘上滤",通俗一点就是把原来子节点要考虑的问题转移到他父节点去考虑。

DeleteMin:

    其实和插入差不多。因为最小堆的最小值就是根,所以把根值取出即可。但我们不能取出之后就不管堆了啊,这时候可以把最后那个节点放到根上,然后再下滤来调整堆。比如像对于上面那个图,取出13后,把16放到13那个位置。但明显14比16小,所以需要下滤调整。

 1 int DeleteMin(PriorityQueue H){
 2
 3     int i,child;
 4     if (H->Size == 0){
 5         printf("empty!");
 6     }
 7     int LastNumber = H->Element[H->Size];
 8     int MinNumber = H->Element[1];
 9     H->Size--;
10     for (i = 1; 2 * i <= H->Size; i = child){
11         child = 2 * i;
12         if (child != H->Size&&H->Element[child + 1] < H->Element[child]){  //这句很重要,因为可能只有一个孩子
13             child++;
14         }
15         if (LastNumber > H->Element[child]){
16             H->Element[i] = H->Element[child];
17         }
18         else
19             break;
20     }
21     H->Element[i] = LastNumber;
22     return MinNumber;
23
24 }

其他还有很多操作:

①DecreaseKey:上滤即可

②Delete: 先把key decrease成负无穷,然后再deleteMin即可。

③Min-Heapify:就是在假设左子树右子树都符合堆的性质时,根有可能不符合,进行调整使其符合。

    代码和DeleteMin差不多:

  

 1 void Min_Heapify(PriorityQueue H,int Num){
 2     int child, i;
 3     int root = H->Element[Num];
 4     printf("%d", root);
 5     for (i = Num; 2 * i <= H->Size; i = child){
 6         child = 2 * i;
 7         if (child != H->Size&&H->Element[child + 1] < H->Element[child]){  //这句很重要,因为可能只有一个孩子
 8             child++;
 9         }
10         if (root > H->Element[child]){
11             H->Element[i] = H->Element[child];
12         }
13         else
14             break;
15     }
16     H->Element[i] =root;
17 }

④BuildHeap:

  首先定理: 当用数组存储n个元素的堆时,叶节点下标分别为[n/2]+1,[n/2]+2……n.(向下取整)

                 因为①:Size为偶数时:2i=H->Size,所以i<=(H->Size)/2

②:Size为奇数时:2i+1=H->Size,所以i<=(H->Size-1)/2。

因此:我们建堆如下:只要从叶节点的前一个元素开始,依次对每一个元素进行一次维护最小堆性质的处理即可。再一次以上面的图为例。只要依次对14,21,13进行Min_Heapify就可以了。

   

1 void Build_Heap(PriorityQueue H, int* a,int length){
2     H->Element = a;
3     H->Size = length;
4     int i;
5     for (i = length / 2 ; i >= 1; i--){
6         Min_Heapify(H, i);
7     }
8 }

 可以证明:Build_Heap的运行时间为O(N)。

      

  

时间: 2024-07-28 21:12:26

⑥二叉堆的相关文章

二叉堆(binary heap)

堆(heap) 亦被称为:优先队列(priority queue),是计算机科学中一类特殊的数据结构的统称.堆通常是一个可以被看做一棵树的数组对象.在队列中,调度程序反复提取队列中第一个作业并运行,因而实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权.堆即为解决此类问题设计的一种数据结构. 本文地址:http://www.cnblogs.com/archimedes/p/binary-heap.html,转载请注明源地址. 逻辑定义 n个

算法—二叉堆

实现栈或是队列与实现优先队列的最大不同在于对性能的要求.对于栈和队列,我们的实现能够在常数时间内完成所有操作:而对于优先队列,插入元素和删除最大元素这两个操作之一在最坏情况下需要线性时间来完成.我们接下来要讨论的基于数据结构堆的实现能够保证这两种操作都能更快地执行. 1.堆的定义 数据结构二叉堆能够很好地实现优先队列的基本操作.在二叉堆的数组中,每个元素都要保证大于等于另两个特定位置的元素.相应地,这些位置的元素又至少要大于等于数组中的另两个元素,以此类推.如果我们将所有元素画成一棵二叉树,将每

二叉堆 - 最小堆

二叉堆:一般我们拿来用的就是最大堆和最小堆. 最小堆:每个节点的值比它的左右子节点的值要大. 代码实现如下:参考Mark Allen Weiss<数据结构和算法分析>(第二版) 1 #include <cstdio> 2 #include <cstdlib> 3 4 #define MIN (1<<(sizeof(int)*8-1)) 5 6 typedef int Item; 7 typedef struct HeapStruct* heap; 8 9 s

Bestcoder4——Happy Three Friends(二叉堆)

本文出自:http://blog.csdn.net/svitter Happy Three Friends Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 0    Accepted Submission(s): 0 Problem Description Dong-hao , Grandpa Shawn , Beautful-leg

堆排序:什么是堆?什么是最大堆?二叉堆是什么?堆排序算法是怎么样的?PHP如何实现堆排序?

本文标签:  堆排序 php php算法 堆排序算法 二叉堆 数据结构 REST   服务器 什么是堆 这里的堆(二叉堆),指得不是堆栈的那个堆,而是一种数据结构. 堆可以视为一棵完全的二叉树,完全二叉树的一个"优秀"的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示,每一个结点对应数组中的一个元素. 数组与堆之间的关系 二叉堆一般分为两种:最大堆和最小堆. 什么是最大堆 堆中每个父节点的元素值都大于等于其孩子结点(如果存在),这样的堆就是一个最大堆 因此,最大堆中的

poj 3253 初涉二叉堆 模板题

这道题很久以前就做过了 当时是百度学习了优先队列 后来发现其实还有个用sort的办法 就是默认sort排序后 a[i]+=a[i-1] 然后sort(a+i,a+i+n) (大概可以这样...答案忘了...) 嗯...其实标准解法是二叉堆.. 主函数里面的while里面wa了好多次.. 每次都选最小的那俩相加 再放回去 #include<stdio.h> #include<string.h> #include<algorithm> using namespace std

在A*寻路中使用二叉堆

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

堆、二叉堆、堆排序

堆.二叉堆.堆排序 堆的概念: 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

AC日记——二叉堆练习3 codevs 3110

3110 二叉堆练习3 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 给定N(N≤500,000)和N个整数(较有序),将其排序后输出. 输入描述 Input Description N和N个整数 输出描述 Output Description N个整数(升序) 样例输入 Sample Input 5 12 11 10 8 9 样例输出 Sample Output 8 9 10 11 12 数据范围及提示 Data Si

codevs 3110 二叉堆练习3

3110 二叉堆练习3 http://codevs.cn/problem/3110/ 题目描述 Description 给定N(N≤500,000)和N个整数(较有序),将其排序后输出. 输入描述 Input Description N和N个整数 输出描述 Output Description N个整数(升序) 样例输入 Sample Input 5 12 11 10 8 9 样例输出 Sample Output 8 9 10 11 12 数据范围及提示 Data Size & Hint 对于3