引子: 在堆排序中或Top-k相关的问题中,我们知道堆是一个非常重要的结构,具有其他所没有的优势!但是堆的创建是一个值得我们讨论的问题,我们已知向上向下调整法来创建堆!但是这二种方法其实差异很大!并且当我们在用堆排序的时候,我们升序用大堆还是小堆也具有很大差距!对小堆也一样!
那我们来用数学的角度来分析一下他们的复杂度!
分析:
一,向上创建堆
注意:时间复杂度是从最坏的情况来看的!要对二叉树的性质有了解!
首先,我们从向上创建堆的角度来看(我愿意称为多乘多)
如图,是一个树形结构;
ok,老铁我们来看。
我们把总节点数记为N; h为树的层数(把根节点记作为第一层); F(h)为该种创建方法下最坏要进行交换的次数!注意:第二层要交换的次数为1次,第三层交换次数为2次,.......第h层要交换的次数为h-1次
所以我们写出,
F(h)=2^1*1 + 2^2*2 + 2^3*3 + 2^4*4 + 2^5*5 + 2^6*6 + ...... + 2^(h-1)*(h-1); 我们记作1;
2* F(h)= 2^2*1 + 2^3*2 + 2^4*3 + 2^5*4 + 2^6*5 + 2^7*6 + ...... + 2^(h)*(h-1);我们记作2;
2-1=F(h)=2^(h)*(h-1) - [2^1 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + ...... + 2^(h-1)] - 4;
我们用等比公式!
等比求和:
所以F(h)=2 ^ ( h ) * ( h - 1 ) - ( 2 ^ ( h + 1 ) - 2) - 4;
F(h)= ( h - 3 ) * 2 ^ ( h + 1 ) - 2;
我们有二叉树性质得:h=log2(N+1);N=2^h-1;
带入得:( log2(N+1) - 3) * ( N + 1 ) * 2 - 2 ;
根据大O阶所以为 N*log(N)
建堆代码:
void Heapcreat(Heap* hp, HPDataType* a, int n);
二,向下创建堆
注意:向下建堆是从倒属第一个非叶子节点,我们是从下往上做判断的
我愿意称为(少乘少)
推理如下:
向下调整法:
有不懂的铁汁吗?记得发评论区哦!
用堆的升序与降序:
升序:
对于升序,我们是用大根堆还是小根堆呢?如果你不知道,不要紧,我们从小根堆来看,
我们给定一个数组为a={ 10 ,20,30,40,60,80} 如图:
那就是: 10
20 30
40 60 80
我们看第一次,我们取10,然后,我们该找第二小的数了也就是次小。
那我们该如何找呢?其实这个时候,小根排序的弊端就出来了!
1,我们如果向前覆盖,那破坏了父子关系,兄弟变父子了,违反常理!
2,如果我们不覆盖,那我们就要重新建堆,那它的复杂度是O(n),不如排序,删掉一个再一遍一遍找最小!
那我们只能用大根堆了!
思路:那大根堆如何操作呢?其实和Headpop()原理差不多,我们找到最大的数(根节点)与最后一个数进行交换,在size--,注意此时,并没有删掉最大的数,只是不把它包括在内,然后我们进行向下调整,找到第二大的,放在根节点!
代码如下:
我们先建堆,要用小堆建;
降序:那降序,不言而喻,就是用小堆了
思路:那大小堆如何操作呢?其实和Headpop()原理差不多,我们找到最小的数(根节点)与最后一个数进行交换,在size--,注意此时,并没有删掉最小的数,只是不把它包括在内,然后我们进行向下调整,找到第二小的,放在根节点!
也很简单,只要细心一点,写完可私信我哦!
ok,今天就分享到此了,大家多多支持!
下一篇,我们将探讨Top-k以及二叉树遍历!