二叉堆 Binary Heap

Binary Heap的基本概念

  • Heap是一个完全二叉树 (Complete Tree)
  • 根节点最大是Max Heap, 根节点最小是Min Heap
  • Max Heap: Heap的每个节点都大于等于它的子节点
  • Min Heap: Heap的每个节点都小于等于它的子节点
  • Heap一般通过数组实现。
  • 节点N(N是下标)的两个子节点的下标分别为 2N+1 和 2N+2
  • 节点N(N是下标)的父节点的下标为
    如果 N%2 == 0,父节点为 (N-2)/2
    如果 N%2 == 0,父节点为(N-1)/2

数组: 9 8 7 6 5 4 3 2 1
在这里插入图片描述
数组: 1 2 3 4 5 6 7 8 9
在这里插入图片描述

Binary Heap的核心原理

siftUp

  • 对于任意节点,不断的和父节点比较,如果小于父节点则交换(MinHeap),直至不能继续上浮

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
siftUp代码

protected void siftUp(int i) {
		//如果输入Index超出范围,返回0
		if(i <= 0) {
			return;
		}
		//找出输入节点的父节点
		int parentIndex = (i % 2 == 0) ? (i - 2) / 2: (i - 1) / 2;
		//和父节点比较
		if(compare(parentIndex,i)) {
			swap(parentIndex, i);
			//继续上浮
			siftUp(parentIndex);
		}
		else {
			return;
		}
	}

siftDown

  • 对于任意节点,不断的和子节点中较大的比较(MaxHeap),如果小于此节点则交换(MinHeap),直至不能继续下沉

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

protected void siftDown(int i) {
		//两个子节点全部越界
		if (i* 2 + 2 >= size && i*2 +1 >= size) {
			return;
		}
		
		int targetIndex = 0;
		//如果2N+1没有越界但是2N+2越界
		//则子节点为2N+1
		if(2*i+2 >= size) {
			targetIndex = 2*i+1;
		}
		else {
		    //比较两个子节点的值,选大的一个
			targetIndex = (compare(2*i+1, 2*i+2)) ? 2*i+2 : 2*i+1;
		}
		//两个节点比较
		if(compare(i, targetIndex)) {
			swap(i, targetIndex);
			//继续下沉
			siftDown(targetIndex);
		}
		else {
			return;
		}
}

Binary Heap的基本方法

Heapify

  • 将一个数组转换为heap
  • 方法是对所有的 Inner Node 进行siftDown操作,从最后一个InnerNode开始
  • 最后一个 Inner Node的坐标为 size/2 - 1

如下图,所有的红点为Inner Node.
其中最后一个Inner Node (Node 4)的坐标为 9/2 - 1 = 3
执行下沉的顺序为 :4 3 2 1

数组: 1 2 3 4 5 6 7 8 9
在这里插入图片描述
Heapify 代码

	public void heapify() {
		for(int i = size/2-1; i >= 0; i--){
			siftDown(i);
		}
	}

Push

  • 在heap中加入一个新值
  • 将新值放在数组的末尾(完全二叉树的末尾)然后执行shiftUp操作
  • 不用shiftDown完成push方法是因为不能把根替换成新元素,否则就破坏了树的结构
public void push(Object val) {
	checkCapacity();
	//放置末尾
	heapArray[size] = val;
	siftUp(size);
	size++;
}

Pop

  • 将heap中的根元素(数组的第一个元素)pop出来
  • 方法:
  • 将根元素和heap的最后一个元素进行交换
  • 将此时的最后一个元素(也就是之前的根元素)置空
  • 对此时的根元素进行shiftDown操作

对下面的heap进行 Pop()操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public Object pop() {
	if(!isEmpty()){
		//首尾交换位置
		swap(0, size-1);
		Object temp = heapArray[size-1];
		//将最好一个置为null
		heapArray[size-1] = null;
		size--;
		//对第一个元素siftDown
		siftDown(0);
		return temp;
	}
		
	System.out.println("Empty Heap");
	return null;
}

Binary Heap的时间复杂度

时间复杂度解释
heapifyO(N)每一次shiftdown的时间复杂度是和当前节点的高度相关的,把最小堆看做一棵二叉树,叶子节点一层的下移最多是0,第二层的下移时间最多是1,第三层是2,依此类推;而每一层的最多节点数,对于一棵满二叉树来说,第k层的节点数是2^(h-k),h是二叉树的高度;所以堆化的最大时间复杂度就是Sum((k-1) * 2^(h-k)), k from 1 to h,计算之后得到的是2^h-h-1,也就是n-log(n)-1 = O(n)
pushO(logn)最坏情况就是一直上浮到根元素,复杂度是树的层数,也就是logN
popO(logn)最坏情况就是交换完之后,根元素一直siftDown到最后一层,复杂度是树的层数,也就是logN

Binary Heap的实现

Heap Interface

package heap;

public interface HeapInterface {	
	
	public void push(Object val);
	public void heapify();
	public Object pop();
	public Object peek();
}

Heap Abstract

package heap;

import java.util.Iterator;

public abstract class HeapAbstract implements HeapInterface {

	public int size;
	protected int capacity;
	protected Object [] heapArray;
	
	public abstract boolean compare(int j, int i);
	
	//Public Methods
	@Override
	public void push(Object val) {
		checkCapacity();
		heapArray[size] = val;
		siftUp(size);
		size++;
	}
	
	@Override
	public Object pop() {
		if(!isEmpty()){
			swap(0, size-1);
			Object temp = heapArray[size-1];
			heapArray[size-1] = null;
			size--;
			siftDown(0);
			return temp;
		}

		System.out.println("Empty Heap");
		return null;
	}
	
	@Override
	public Object peek() {
		if(!isEmpty()) {
			return heapArray[0];
		}
		
		return null;
	}
	
	//Protected Methods
	public void heapify() {
		for(int i = size/2-1; i >= 0; i--){
			siftDown(i);
		}
	}

	protected void siftDown(int i) {
		if (i* 2 + 2 >= size && i*2 +1 >= size) {
			return;
		}
		
		int targetIndex = 0;
		if(2*i+2 >= size) {
			targetIndex = 2*i+1;
		}
		else {
			targetIndex = (compare(2*i+1, 2*i+2)) ? 2*i+2 : 2*i+1;
		}
	
		if(compare(i, targetIndex)) {
			swap(i, targetIndex);
			siftDown(targetIndex);
		}
		else {
			return;
		}
}

	protected void siftUp(int i) {
		if(i <= 0) {
			return;
		}
		
		int parentIndex = (i % 2 == 0) ? (i - 2) / 2: (i - 1) / 2;
		if(compare(parentIndex,i)) {
			swap(parentIndex, i);
			siftUp(parentIndex);
		}
		else {
			return;
		}
	}

	
	protected void checkCapacity() {
		if(size < capacity){
			return;
		}
		
		Object [] temp = new Object[capacity];
		for(int i =0; i < capacity; i++){
			temp[i] = heapArray[i];
		}
			
		heapArray = new Object[capacity *2];
		for(int j=0; j < capacity; j++){
			heapArray[j] = temp[j];
		}
		capacity = capacity *2;
	}
	
	protected void swap(int a, int b) {
		Object temp = heapArray[a];
		heapArray[a] = heapArray[b];
		heapArray[b] = temp;
	}
	
	
	protected void display() {
		for(int i = 0; i < size; i++) {
			System.out.print( " " + heapArray[i]);
		}
		System.out.println();
	}
	
	protected boolean isEmpty() {
		if(size == 0) {
			return true;
		}
		
		return false;
	}
	
	protected int size() {
		return size;
	}
}

Max Heap

package heap;

import java.util.Iterator;

public class MaxHeap extends HeapAbstract {

	public MaxHeap() {
		capacity = 10;
		heapArray = new Object[capacity];
		size = 0;
	}
	
	
	public MaxHeap(Object [] input) {
		heapArray = input;
		capacity = input.length;
		size = input.length;
		heapify();
	}
	
	
	public MaxHeap(int length) {
		capacity = length;
		heapArray = new Object[size];
		size = 0;
	}
	
	@Override
	public boolean compare(int j, int i ) {
		if((Integer)heapArray[j] < (Integer)heapArray[i]) {
			return true;
		}
		
		return false;
	}
	
	public static void main(String[] args) {
		Object [] array = {1,2,3,4,5,6};
		MaxHeap myHeap = new MaxHeap(array);
		myHeap.display();	
	}
}

Min Heap

package heap;

import java.util.Iterator;

public class MinHeap extends HeapAbstract {
	
	public MinHeap() {
		capacity = 10;
		heapArray = new Object[capacity];
		size = 0;
	}
	
	public MinHeap(Object [] input) {
		heapArray = input;
		capacity = input.length;
		size = input.length;
		heapify();
	}
	
	public MinHeap(int length) {
		capacity = length;
		heapArray = new Object[size];
		size = 0;
	}

	@Override
	public boolean compare(int j, int i ) {
		if((Integer)heapArray[j] > (Integer)heapArray[i]) {
			return true;
		}
		
		return false;
	}
	
	public static void main(String[] args) {
		Object [] array = {6,5,4,3,2,1};
		MinHeap myHeap = new MinHeap(array);
		myHeap.display();	
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值