为什么在BuildHeap中siftdown要优于siftup

文章目录

一.定义一个Array-based MaxHeap

class MaxHeap{
private:
	int size;
	int n;
	int* Heap;
	void siftdown(int);
	void siftup(int);
public:
	void BuildHeapDown();
	void BuildHeapUp();
	bool RemoveMax();
	bool isleaf(int pos){
		return (pos > (n/2 - 1));
	}
	int parent(int pos){
		return floor((pos-1)/2);
	}
}

二. 使用siftdown构建BuildHeap

void MaxHeap::siftdown(int pos){
	while(!isleaf(pos)){
		int j = 2*pos+1;
		int rc = 2*pos+2;
		if(Heap(j) < Heap(rc)) j = rc;  //取两子之大
		if(Heap[pos] < Heap[j]){  //如果pos处值小于子值,那么调换位置
			int temp = Heap[j];
			Heap[j] = Heap[pos];
			Heap[pos] = temp;
			pos = j; //继续向下比较
		}
	}
}
void MaxHeap::BuildHeapDown(){
	//对于非叶子结点,从最后一个节点开始往前依次进行siftdown
	for(int i = (n/2 - 1); i>=0; i--) siftdown(i);
}

时间复杂度: 假设现在有一个满二叉树,node数量为 n n n, 最差情况下的时间复杂度为
∵ T n = ∑ i = 1 log ⁡ ( n + 1 ) ( log ⁡ ( n + 1 ) − i ) ∗ 2 i − 1 \because Tn = \sum_{i=1}^{\log (n+1)} {\left( \log (n+1) -i\right)} *{2}^{i-1} ∵Tn=i=1∑log(n+1)​(log(n+1)−i)∗2i−1 令d = log(n+1),展开之后利用错位相减法可以求出  T n = n + 1 2 \text{令d = log(n+1),展开之后利用错位相减法可以求出 }Tn=\frac{n+1}{2} 令d = log(n+1),展开之后利用错位相减法可以求出 Tn=2n+1​ ∴ T n = O ( n ) \therefore Tn = O(n) ∴Tn=O(n)

三. 使用siftup构建BuildHeap

void MaxHeap::siftup(int pos){
	while(pos!=0){//只要不是root,都和自己的parent比较
		if(Heap[pos] > Heap[parent(pos)]){
			int temp = Heap[pos];
			Heap[pos] = Heap[parent(pos)];
			Heap[parent(pos)] = temp;
			pos = parent(pos); //继续向上比较
		}
	}
}
void MaxHeap::BuildHeapUp(){
	for(int i = 1; i<n; i++) siftup(i); // 从第二行开始,逐个进行siftup
}

时间复杂度: 假设现在有一个满二叉树,node数量为 n n n, 最差情况下的时间复杂度为
∵ T n = ∑ i = 1 log ⁡ n 2 i ⋅ i \because Tn = \sum_{i=1}^{\log n} {2}^{i} ·i ∵Tn=i=1∑logn​2i⋅i ∴ T n = O ( n log ⁡ n ) \therefore Tn = O(n{\log n}) ∴Tn=O(nlogn)

四.综合分析

(一)时间复杂度方面

首先,我们通过分析,分别计算出了两种建堆方式的时间复杂度。通过计算结果,我们看出通过 s i f t d o w n siftdown siftdown来进行建堆的时间复杂度更低,为 O ( n ) O(n) O(n)。
其实,从直观角度也可以得到这一结论。首先,我们要明确一点:节点数量随着深度增加是呈指数级增长的,而随着深度的加深, B u i l d H e a p D o w n BuildHeapDown BuildHeapDown的调用时间是逐渐变低的。而 B u i l d H e a p U p BuildHeapUp BuildHeapUp的调用时间则会逐渐增加,所以根据 T = ∑ i = 1 n T i m e ( i ) T = \sum_{i=1}^{n} Time(i) T=∑i=1n​Time(i)我们也可以得出 B u i l d H e a p D o w n BuildHeapDown BuildHeapDown的时间复杂度更低。

(二)对于实现ADT方面

我们采用 s i f t d o w n siftdown siftdown是更有利于其他算法的实现的。比如在进行 R e m o v e M a x RemoveMax RemoveMax操作的时候,只需要将root节点和末尾节点换位并修改 n = n − 1 n=n-1 n=n−1,然后进行 s i f t d o w n siftdown siftdown就可以了。只需要 O ( log ⁡ n ) O(\log n) O(logn)的时间;

bool MaxHeap::RemoveMax(int &t){
	if(n==0) return false;
	t = Heap[0]; //保存max
	Heap[0] = Heap[--n] 
	Heap[n] = t;
	if(n!=0) siftdown(0);
	return true;
}
上一篇:python泰波那契序列(leetcode)


下一篇:Android中Toast的显示和隐藏分析