二項堆的操作

class Node {
	Node parent;
	Node child;
	Node sibling;
	int key;
	int degree;

	public Node(int key) {
		this.key = key;
		this.degree = 0;
		this.child = null;
		this.parent = null;
		this.sibling = null;

	}
}

public class BinomialHeap {
	public Node head;

	public BinomialHeap() {
		head = null;
	}

	// 尋找最小關鍵字
	public Node min() {
		Node n = head;
		Node m = null;
		int min = head.key;

		while (null != n) {
			if (min > n.key) {
				min = n.key;
				m = n;
			}
			n = n.sibling;
		}

		return m;
	}

	// 按度的大小歸併兩個二項堆
	public void merge(BinomialHeap heap) {
		Node node;
		Node head1 = this.head;
		Node head2 = heap.head;

		// 確定head
		if (head1.degree < head2.degree) {
			node = head1;
			head1 = head.sibling;
		} else {
			this.head = head2;
			node = heap.head;
			head2 = head2.sibling;
		}

		// 歸併二項堆
		while (head1 != null && head2 != null) {
			if (head1.degree < head2.degree) {
				node.sibling = head1;
				node = head1;
				head1 = head1.sibling;
			} else {
				node.sibling = head2;
				node = head2;
				head2 = head2.sibling;
			}
		}

		if (head1 == null) {
			node.sibling = head2;
		} else {
			node.sibling = head1;
		}
	}

	// 合併二叉樹
	public void link(Node big, Node small) {
		big.parent = small;
		big.sibling = small.child;
		small.child = big;
		small.degree++;
	}

	// 合併二項堆(把this和heap合併爲一個新的this)
	public void union(BinomialHeap heap) {
		// 處理空值的情況
		if (null == heap.head) {
			return;
		}
		if (null == this.head) {
			this.head = heap.head;
			return;
		}

		// 沒有空值開始合併
		merge(heap);

		Node pre = null;
		Node x = this.head;
		Node next = x.sibling;

		while (null != next) {
			if ((x.degree != next.degree)
					|| (null != next.sibling && next.sibling.degree == x.degree)) {
				pre = x;
				x = next;
			} else if (x.key <= next.key) {
				x.sibling = next.sibling;
				link(next, x);
			} else {
				if (null == pre) {
					this.head = next;
				} else {
					pre.sibling = next;
				}
				link(x, next);
				x = next;
			}
			next = x.sibling;
		}
	}

	// 插入新結點
	public void insert(int key) {
		Node node = new Node(key);
		BinomialHeap h = new BinomialHeap();
		h.head = node;
		union(h);
	}

	// 查找某結點
	public Node find(int key, Node node) {
		if (null == node) {
			return null;
		}
		if (key == node.key) {
			return node;
		}
		Node n1 = find(key, node.sibling);
		Node n2 = find(key, node.child);
		if (n1 != null || n2 != null) {
			if (n1 != null) {
				return n1;
			} else {
				return n2;
			}
		} else {
			return null;
		}
	}

	// 抽取關鍵字最小的結點
	public void extract_min() {
		Node min = min();
		Node premin = head;

		// 把最小值所在的二項樹獨立出來
		if (min != head) {
			while (premin.sibling != min) {
				premin = premin.sibling;
			}
			premin.sibling = min.sibling;
		} else {
			head = head.sibling;
		}
		min.sibling = null;

		// 把最小值所在的二項樹重新組織成二項堆
		BinomialHeap bh = new BinomialHeap();

		// 讓min脫離出來
		Node child = min.child;
		child.parent = null;
		min.child = null;

		// 反轉min的孩子使之成爲新的二項堆(這也是反轉單向鏈表的一般方法)
		Node pre, cur, ne;
		pre = child;
		cur = child.sibling;
		pre.sibling = null;
		while (cur != null) {
			ne = cur.sibling;
			cur.parent = null;
			cur.sibling = pre;
			pre = cur;
			cur = ne;
		}
		bh.head = pre;

		// 分離出來的新二項堆與原來的合併
		union(bh);
	}

	// 減小某結點的值
	public void decrease_key(int key, int nkey) {
		if (nkey > key) {
			System.out.print("error,輸入的數比原結點的值大\n");
			return;
		} else {
			Node n = find(key, head);
			if (n == null) {
				System.out.print("結點不存在\n");
				return;
			} else {
				n.key = nkey;
				Node nparent = n.parent;
				while (nparent != null && n.key < nparent.key) {
					int temp = n.key;
					n.key = nparent.key;
					nparent.key = temp;

					n = nparent;
					nparent = nparent.parent;
				}
			}
		}
	}

	// 刪除結點
	public void delete(int key) {
		Node n = find(key, head);
		if (n == null) {
			System.out.print("結點不存在\n");
			return;
		} else {
			decrease_key(key, -Integer.MAX_VALUE);
			extract_min();
		}
	}

	// 遍歷二項堆
	public void traversal(Node node) {
		if (null == node) {
			return;
		}
		System.out.print(node.key + ",");
		traversal(node.sibling);
		traversal(node.child);
	}

	public static void main(String[] args) {
		int[] E = { 0, 12, 90, 1, 85, 12, 3, 13, 49, 55, 10, 3, 31, 97, 19, 93,
				41, 55, 56, 82, 2, };
		BinomialHeap heap = new BinomialHeap();

		// 建立二項堆
		for (int i = 0; i < E.length; i++) {
			heap.insert(E[i]);
		}
		// 遍歷
		heap.traversal(heap.head);

		// 查找
		Node n = heap.find(87, heap.head);
		System.out.println();
		if (null == n) {
			System.out.print("結點不存在\n");
		} else
			System.out.print("要找的結點值爲" + n.key + "\n");

		// 輸出最小值
		System.out.println("最小值爲:" + heap.min().key);

		// 刪除結點
		heap.delete(19);

		heap.traversal(heap.head);
	}
}


轉自:http://hi.baidu.com/%D0%D0%D7%DF%D4%DA%BF%D5%D6%D0/blog/item/7523d112268f0a41f819b89f.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章