数据结构基础加强之最小堆的实现与堆排序

 数据结构基础加强之最小堆的实现与堆排序

二叉堆的形式:

最小堆:根结点的值是所有堆结点中最小者,并且每个结点的值比其孩子结点小。
最大堆:根结点的值是所有堆结点中最大者,并且每个结点的值比其孩子结点大。


最小堆通常都是一棵完全二叉树,可以用数组来存储最小堆的值。

堆中父结点与子结点 的关系:

heap[father * 2] = heap[leftChild];  heap[father * 2 + 1] = heap[rightChild];

最大堆与最小堆基本做法基本一致,只要把实现代码中的小于变大于,大于变小于即可

最小堆的初始化:依次将节点加入堆数组中,每次进入新的结点加到堆数组的尾部,依次与父结点相比较,如果小于父结点则交换二者的位置。

	//添加元素
	public void add(int item){
		size++;
		heap[size] = item;
		int curr = size;
		while (heap[curr] < heap[getFather(curr)]) {
			swap(curr,getFather(curr));
			curr = getFather(curr);
		}
	}

最小堆的调整:一处最小堆的根节点之后,需要调整堆数组使之成为一个新的堆。

可以采用以下方式来调整堆:将堆数组最后一个元素放到堆数组的首部,依次与左右子结点比较,把较小的值与根节点交换,然后递归,直至当前节点是叶子节点为止。

	//元素下移调整
	public void pushDown(int pos){
		int smallChild;
		while (!isLeaf(pos)) {
			smallChild = getLeftChild(pos);
			//在父节点知道的情况下,左节点不会出现越界情况,右节点可能越界
			if (smallChild <= size) { 
				if (getRightChild(pos) <= size && heap[smallChild] > heap[smallChild + 1]) {
					smallChild++;
				}
				if (heap[pos] > heap[smallChild]) {
					swap(pos,smallChild);
					pos = smallChild;
				}else {
					return;
				}
			}else {
				return;
			}
		}
	}

堆排序的实现:

利用建立的堆实现堆排序比较简单。将数组中的元素依次加入最小堆中,每次取出堆数组的第一个元素,即最小值放到待排序数组的首部。每次取出堆数组第一个元素后,堆数组会自己调整,让它继续是一个最小堆。依次取出最数组的中的第一个元素,依次放入待排序数组中,直至堆数组为空,此时待排序数组是有序的。

堆排序实现代码:

import heap.Heap;

public class HeapSort {

	public static void main(String[] args) {

		int[] array = { 1, 9, 6, 8, 7, 3, 4, 2, 0 };
		solution(array);
		for (int i : array) {
			System.out.print(i + " ");
		}
	}

	private static void solution(int[] array) {

		Heap heap = new Heap(10);
		for (int i : array) {
			heap.add(i);
		}
		for (int i = 0;i < array.length;i++) {
			array[i] = heap.delete();
		}
	}

}
最小堆的实现代码:

public class Heap {

	private int[] heap;
	private int size;//当前节点数
	@SuppressWarnings("unused")
	private int max; //最大节点数
	
	//使用数组存储堆元素  根节点位于数组下表为1的元素
	public Heap(int max){
		this.max = max;
		heap = new int[max];
		size = 0;
		heap[0] = Integer.MIN_VALUE;
	}
	//获得父节点的位置
	public int getFather(int index){
		return index / 2;
	}
	//获得左子节点的位置
	public int getLeftChild(int index){
		return index * 2;
	}
	//获得右子节点的位置
	public int getRightChild(int index){
		return index * 2 + 1;
	}
	//判断节点是否为根节点
	public boolean isLeaf(int index){
		if (index > size / 2 && index < size) {
			return true;
		}else{
			return false;
		}
	}
	//判断堆是否为空
	public boolean isEmpty(){
		if (size == 0) {
			return true;
		}else{
			return false;
		}
	}
	//元素交换
	public void swap(int pos1,int pos2){
		int temp = heap[pos1];
		heap[pos1] = heap[pos2];
		heap[pos2] = temp;
	}
	//打印所有节点
	public void print(){
		for (int i = 1;i <= size;i++) {
			System.out.print(heap[i] + " ");
		}
	}
	//添加元素
	public void add(int item){
		size++;
		heap[size] = item;
		int curr = size;
		while (heap[curr] < heap[getFather(curr)]) {
			swap(curr,getFather(curr));
			curr = getFather(curr);
		}
	}
	//删除并返回根节点
	public int delete(){
		int firstItem = heap[1];
		swap(1, size);
		size--;
		if (size != 1) {
			pushDown(1);
		}
		return firstItem;
	}
	//元素下移调整
	public void pushDown(int pos){
		int smallChild;
		while (!isLeaf(pos)) {
			smallChild = getLeftChild(pos);
			//在父节点知道的情况下,左节点不会出现越界情况,右节点可能越界
			if (smallChild <= size) { 
				if (getRightChild(pos) <= size && heap[smallChild] > heap[smallChild + 1]) {
					smallChild++;
				}
				if (heap[pos] > heap[smallChild]) {
					swap(pos,smallChild);
					pos = smallChild;
				}else {
					return;
				}
			}else {
				return;
			}
		}
	}
}
具体代码可以参考:https://github.com/Li-JY/algorithm-and-datastructure/tree/master/src/heap


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值