数据结构之堆Heap和优先队列PriorityQueue--第一篇--堆的实现

一、堆简介

这里所说的堆是二叉堆,二叉堆是一颗完全二叉树

二叉堆可以分为最大堆和最小堆

最大堆:堆中任意父结点的值总不小于其孩子结点的值

最小堆:堆中任意父结点的值总不大于其孩子结点的值

堆可以用数组来实现
假设数组从下标为0处开始存放元素,则对于任意的一个结点 i, 它的左孩子结点下标为 2i + 1, 它的右孩子结点下标为 2i + 2, 它的父结点的下标为 (i - 1) / 2;
若数组从下标为1处开始存放元素,则对于任意的一个结点i,它的左孩子结点下标为 2i,它的右孩子结点下标为 2i + 1,它的父结点的下标为 i / 2。
这里使用了* 动态数组 *
public class MaxHeap<E extends Comparable <E>> {
	private Array<E> array;
	
	public MaxHeap(int capacity){
		array = new Array<>(capacity);
	}
	
	public MaxHeap(){
		array = new Array<>();
	}
	
	//将数组转化为堆的形式(Heapify)
	public MaxHeap(E[] arr) {
		array = new Array<>(arr);
		for(int i = parentIndex(arr.length - 1); i >= 0; i-- ) {
			siftDown(i);
		}
	}
	
	//返回堆中元素个数
	public int getSize() {
		return array.getSize();
	}
	
	//判断堆是否为空
	public boolean isEmpty() {
		return array.isEmpty();
	}
	
	/********************辅助方法************************/
	//1. 返回索引所对应元素的父结点索引
	public int parentIndex(int index) {
		if(index > array.getSize() || index < 0)
    		throw new IndexOutOfBoundsException("Index should between 0 to size");
		
		if(index == 0)
			System.out.println("Index of zero has no parent node");
		
		return (index - 1) / 2;
	}
	//2. 返回索引所对应元素的左孩子索引
	public int leftChildIndex(int index) {
		if(index > array.getSize() || index < 0)
    		throw new IndexOutOfBoundsException("Index should between 0 to size");
		return 2 * index + 1;
	}
	
	// 3. 返回索引所对应元素的左孩子索引
	public int rightChildIndex(int index) {
		if (index > array.getSize() || index < 0)
			throw new IndexOutOfBoundsException("Index should between 0 to size");
		return 2 * index + 2;
	}
	/***************************************************************/
	
	// 向堆中添加元素
	/*
	 * 1. 先将元素添加到数组的尾部,即让它成为最后一个叶子结点
	 * 2. 让它与其父结点进行比较,若不满足二叉堆的条件,则二者交换位置(上浮操作)
	 * 3. 对其父结点进行 步骤2 的操作,重复此操作直至父结点为根结点
	 */
	public void add(E element) {
		//添加元素到数组尾部
		array.addLast(element);
		//上浮操作
		siftUp(array.getSize() - 1);
	}

	// 上浮
	private void siftUp(int index) {
		while (index > 0 && array.get(index).compareTo(array.get(parentIndex(index))) > 0) {
			array.swap(index,parentIndex(index));
			index = parentIndex(index);
		}
	}
	
	//找出最大元素(在数组中为下标为0的元素)
	public E findMax() {
		if(array.getSize() == 0)
			throw new IllegalArgumentException("Can not findMax when heap is empty.");
        return array.get(0);
	}
	
	//取出堆中的最大元素
	/*
	 * 最大元素即为根结点所对应的元素,取出之后需要重新构建树
	 * 思路:
	 * 1. 让根结点和最后一个结点交换位置(当前数组中最后一个元素)
	 * 2. 删除最后一个结点(此时即为最大结点)
	 * 2. 对根结点进行下沉操作
	 */
	public E extractMax() {
		E max = findMax();
		//交换
		array.swap(0, array.getSize() - 1);
		//删除
		array.removeLast();
		//下沉
		siftDown(0);
		return max;
	}
	
	//下沉
	/*
	 * 作用:判断当前结点是否满足堆的定义,
	 * 不满足时的操作:
	 * 1. 找出其孩子结点中值较大的那一个
	 * 2. 父结点和较大孩子结点进行交换
	 * 3. 递归向下依次进行
	 */
	private void siftDown(int index) {
		//要判断当前结点的孩子结点是否存在(当左孩子不存在时则一定不存在孩子)
		while(leftChildIndex(index) < array.getSize()) {
			int maxIndex = leftChildIndex(index);
			
			if(maxIndex + 1 < array.getSize() && 
			   (array.get(maxIndex + 1)).compareTo(array.get(maxIndex)) > 0){
				   maxIndex++;
			   }
			if(array.get(maxIndex).compareTo(array.get(index)) <= 0) {
				break;
			}
			array.swap(index, maxIndex);
			index = maxIndex;
		}
	}
	
	//替换堆中的最大元素为element
	public E repalce(E element) {
		E temp = array.get(0);
		array.set(0, element);
		siftDown(0);
		return temp;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值