简单易懂的树、堆讲解

树、堆算法

 

树:

一、一课树中的任意两个结点有仅有惟一的一条路径连通。
二、一棵树若是有n个结点,那么它必定刚好有n-1条边。
三、在一棵树中加一条边将会构造一个回路。数组

满二叉树:二叉树全部的叶结点都有一样的深度。
深度为:n,结点数:2**n - 1数据结构

 

彻底二叉树

若是一棵二叉树除了最右边位置上有一个或者几个叶结点缺乏外,其余是丰满的,那么这样的二叉树就彻底二叉树。严格的定义是:若设二叉树的高度为h,除h层外,其余各层(1~h-1)的结点数都达到最大个数,第n层从右向左连续缺若干个结点,则这个二叉树就是彻底二叉树。优化

 

 

经过上图咱们发现,若是彻底二叉树的一个父结点编号为k,那么它左儿子的编号就是2*k,右儿子的编号就是2*k+1。若是已知儿子(左儿子或右儿子)的编号是x,那么它父结点的编号就是x/2,注意这里只取商的整数部分。
若是一颗彻底二叉树有N个结点,那么这个彻底二叉树的高度为log2N,简写logN,即最多有logN层结点。彻底二叉树的最典型应用就是一个堆。spa

堆—神奇的优先队列

 


最大堆:全部父节点都比儿子结点要大;
最小堆:全部父节点都比儿子结点要小;3d

 

 
很显然最小的数就在堆顶,假设存储这个堆的数组叫作h的话,最小数就是h[1]。接下来,咱们将堆顶的数删除。将新增长的数23放到堆顶。显然加了新数后已经不符合最小堆的特性,咱们须要将新增长的数调整到合适的位置。那如何调整呢?blog

 

 
向下调整!咱们须要将这个数与它的两个儿子2和5比较,选择较小的一个与它交换,交换以后以下。排序

 


咱们发展此时仍是不符合最小堆的特性,所以还须要继续向下调整。因而继续将23与它的两个儿子12和7比较,选择较小一个交换,交换以后以下。队列

 


至此,仍是不符合最小堆的特性,仍须要继续向下调整,直到符合最小堆的特性为止。it

 


如今咱们发现已经符合最小堆的特性了。综上所述,当新增长一个数被放置到堆顶时,若是此时不符合最小堆的特性,则须要将这个数向下调整,直到找到合适的位置为止,使其从新符合最小堆的特性。

 

 
时间复杂度:logN

新增一个数:

新增一个数,只须要将新元素插入到末尾,再根据状况判断新元素是否须要上移,直到知足堆的特性为止。若是堆的大小为 N(即有 N个元素),那么插入一个新元素所须要的时间为 O(logN)。例如咱们如今要新增一个数 3

 

 

构造一个最小堆

 

 
固然目前这个棵树仍然不符合最小堆的特性,咱们须要继续调整以3号结点为根的子树,即将3号结点向下调整。

 


同理,继续调整以2号结点为根的子树,最后调整以1号结点为根的子树。调整完毕以后,整棵树就符合最小堆的特性了。

 

像这样支持插入元素和寻找最大 (小)值元素的数据结构称为优先队列。若是使用普通队列来实现这两个功能,那么寻找最大元素须要枚举整个队列,这样的时间复杂度比较高。若是是已排序好的数据,那么插入一个元素则须要移动不少元素,时间复杂度度依旧很高。而堆就是一种优先队列的实现,能够很好地解决这两种操做。

另外Dijkstr算法中每次找离源点最近的一个顶点也能够用堆来优化,使算法的时间复杂度降到O((M+N)logN)。堆还常常被用来求一个数列中第K大的数,只须要创建一个大小为K的最小堆,堆顶就是第K大的数。

  注:内容来源于《啊哈.算法》

相关文章
相关标签/搜索