小根堆(java)

晚上睡不好觉白天效率就不行,昨天就已经把小根堆的代码写好了,但是因为没什么状态,文章拖到了今天才写。。

首先什么是小根堆:

(1)它是一颗完全二叉树

(2)任意一个节点均小于或等于其左右子节点的关键码(大根堆相反就是了)

因此可以得知,当前树形结构的根节点就是当前整个树形结构最小的节点。。。


至于说这种堆结构有什么作用:

(1)以前本科的时候上数据结构课的时候就有讲过堆排序,好像还不错,O(nlogn)的复杂度

(2)可以用来构造优先权队列。。。。

(3)在libevent库中,定时是采用小根堆来维护(nginx是红黑树)


好了,下面来看看小根堆的插入和删除吧,其实感觉 非常简单诶,比红黑树简单,只需要向上向下浮动就好了,没有红黑树那种左旋右旋,还得染色什么的。。

首先来看节点的插入:

(1)将要插入的节点按照完全二叉树的形式插入到当前树形结构的最末尾

(2)对这个刚刚插入的节点进行向上浮动,浮动的原理是:比较当前的节点和其父节点,如果比父节点小,那么与父节点交换,然后递归的进行,直到浮动不动了或者到了根节点


接下来来看节点的删除:

(1)小根堆的删除是删除当前的根节点,也就是返回当前根节点的值,然后用当前树形结构的最后一个节点来代替根节点

(2)从当前属性结构的最后一个非叶节点开始,向下浮动,浮动的原理是:

   如果有比自己小的子节点,那么与这个子节点交换,然后递归的对刚刚交换下去的子节点进行向下浮动,(如果当前两个子节点都比自己小,那么就与最小的那个交换)


好了,小根堆的原理都差不多了,真心觉得蛮简单的,而且效率也都还不错。。。

下面就是我自己实现的一个小根堆的代码,貌似写的挺挫的。。讲究看吧:

public class SmallHeap <T>{
	
	private Entry<T> root;     //根节点
	private Entry<T> lastNode;  //当前树的最后一个节点
	private Entry<T> last;    //最后一个非叶节点
	private int size;
	
	public SmallHeap() {
		this.root = null;
		this.size = 0;
		this.last = root;
		this.lastNode = root;
	}
	
	public boolean add(T item) {
		if (this.root == null) {
			Entry<T> nowNode = new Entry<T>(item, null, null);
			this.root = this.last = this.lastNode = nowNode;
			return true;
		}
		if (this.last.right != null) {  //表示最后一个非叶节点的子节点已经占满了,那么用下一个节点
			this.last = this.last.next;
		}
		Entry<T> nowNode = new Entry<T>(item, this.last, this.lastNode);
		
		this.lastNode.next = nowNode;    
		this.lastNode = nowNode;
		
		if (this.last.left == null) {
			this.last.left = nowNode;
		} else {
			this.last.right = nowNode;
		}
		this.siftUp(nowNode);
		this.size++;
		return true;
	}
	
	public int size() {
		return this.size;
	}
	
	public T poll() {
		if (root == null) {
			return null;
		}
		T out = root.value;
		root.value = this.lastNode.value;
		
		Entry<T> tlast = this.lastNode;
		if (tlast == root) {
			this.last = null;
			this.lastNode = null;
			this.root = null;
			return out;
		}
		
		this.lastNode = this.lastNode.before;
		this.lastNode.next = null;
		
		if (tlast == tlast.parent.left) {
			tlast.parent.left = null;
			this.last = this.last.before;
		} else {
			tlast.parent.right = null;
		}
		
		Entry<T> node = this.last;
		node = root;

		
		while (node != null) {
			this.siftDown(node);
			node = node.before;
		}
		this.size--;
		return out;
	}
	
	public T top() {
		if (root == null) {
			return null;
		}
		return root.value;
	}
	
	
	
	private void siftDown(Entry<T> node) {
		if (node == null) {
			return;
		}
		while (node.left != null) {
			Comparable now = (Comparable) node.value;
			Comparable child = null;
			Entry<T> childNode;
			
			if (node.right != null) {
				Comparable child1 = (Comparable) node.left.value;
				Comparable child2 = (Comparable) node.right.value;
				
				if (child1.compareTo(child2) < 0) {
					child = child1;
					childNode = node.left;
				} else {
					child = child2;
					childNode = node.right;
				}
				
			} else {
				child = (Comparable) node.left.value;
				childNode = node.left;
				
			}
			if (now.compareTo(child) > 0) {
				node.value = (T)child;
				childNode.value = (T)now;
				node = childNode;
				continue;
			}
			
			
			
			break;
			
		}
	}
	
	
	private void siftUp(Entry<T> node) {
		if (node == null) {
			return;
		}
		while (node.parent != null) {
			Comparable now = (Comparable) node.value;
			Comparable parent = (Comparable) node.parent.value;
			if (now.compareTo(parent) < 0) {
				node.value = (T)parent;
				node.parent.value = (T)now;
				node = node.parent;	
				continue;
			}
			break;
		}
	}
	
	
	
	
	private final class Entry<T> {
		Entry<T> parent;  //父亲节点
		Entry<T> left;
		Entry<T> right;
		
		Entry<T> next;
		Entry<T> before;
		
		T value;
		
		public Entry(T value, Entry<T> parent, Entry<T> before) {
			this.value = value;
			this.parent = parent;
			this.before = before;
		}
	}
	
	public static void main(String args[]) throws IOException {
		
		SmallHeap<Integer> s = new SmallHeap<Integer>();
		int max = 3000000;
		long before = (new Date()).getTime();
		for (int i = max; i > 0; i--) {
			s.add(new Integer((int)(Math.random() * max)));
		}
	
		Integer t = s.poll();
		while (t != null) {
			//System.out.println(t.toString());
			t = s.poll();
		}
		long after = (new Date()).getTime();
		System.out.println(((double)after - (double)before) / 1000);

	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值