一、定義:
1.零路徑長度:某節點的零路徑長度爲該節點到沒有兩個兒子的節點最短距離。
2.左式堆性質:
- 父節點屬性值小於子節點屬性值;
- 堆中的任何節點,其左兒子的零路徑長>=右兒子的零路徑長的二叉樹。
- 任一結點的零路徑長比他的諸兒子結點的零路徑長的最小值多1。
二、實現思路:
1.合併:
左式堆的合併操作基於遞歸實現,算法思路如下:
- 若有一棵樹是空樹,則返回另一棵樹;否則將根節點較大的堆與根節點較小的堆的右子樹合併。
- 使形成的新堆作爲較小堆的右子樹。
- 如果違反了左式堆的特性,交換兩個子樹的位置。
- 更新npl(零路徑長度)。
2.插入
將需要插入的節點當做一棵左式堆樹,進行合併。
3.刪除最小值
刪除根節點,將形成的兩個堆合併
三、代碼實現
public class LeftistHeap<T extends Comparable> {
/**
* Created by Administrator on 2017/6/13.
*/
class Node<T> {
T element;
Node<T> left;//左兒子
Node<T> right;//右兒子
int npl;//零路徑長
Node(T element) {
this(element, null, null);
}
Node(T element, Node<T> left, Node<T> right) {
this.element = element;
this.left = left;
this.right = right;
npl = 0;
}
}
private Node<T> root;
/**
* 構造方法
*/
public LeftistHeap() {
root = null;
}
/**
* 合併堆
*
* @param rhs 另一個左式堆
*/
public void merge(LeftistHeap<T> rhs) {
if (this == rhs) {
return;
}
root = merge(root, rhs.root);
rhs.root = null;
}
public void insert(T x) {
root = merge(root, new Node(x));
}
/**
* 找出最小元素
*
* @return
*/
public T findmin() {
if(isEmpty()){
System.out.println("該左式堆爲空");
}
return root.element;
}
/**
* 刪除最小元素
*
* @return
*/
public T deleteMin() {
if (isEmpty()) {
System.out.println("該左式堆爲空");
}
T minElement = root.element;
root=merge(root.left, root.right);
return minElement;
}
/**
* 是否爲空
*
* @return
*/
public boolean isEmpty() {
return root == null;
}
/**
* 置空
*/
public void makeEmpty() {
this.root = null;
}
/**
* 合併兩個左式堆(判斷過程,真正合並過程由merge1操作)
*
* @param h1
* @param h2
* @return
*/
private Node<T> merge(Node<T> h1, Node<T> h2) {
if (h1 == null)
return h2;
if (h2 == null)
return h1;
if (h1.element.compareTo(h2.element) > 0)
return merge1(h2, h1);
else
return merge1(h1, h2);
}
/**
* 合併兩個左式堆的真正操作 h1的元素小於h2(即h2與h1的右子堆合併)
*
* @param h1
* @param h2
* @return
*/
private Node<T> merge1(Node<T> h1, Node<T> h2) {
if (h1.left == null) {//h1爲單節點
h1.left = h2;
} else {//h1不是單節點
h1.right = merge(h1.right, h2);
if (h1.right.npl > h1.left.npl) {//比較零路徑長,確保左式堆性質不被破壞
swapChildren(h1);
}
h1.npl = h1.right.npl + 1;//零路徑長爲右兒子的零路徑長+1
}
return h1;
}
/**
* 交換左右兒子
*
* @param t
* @return
*/
private void swapChildren(Node<T> t) {
Node<T> temp = t.right;
t.right = t.left;
t.left = temp;
}
private void print(Node t){
if(t==null)
return;
print(t.left);
System.out.println(t.element+":"+t.npl);
print(t.right);
}
public static void main(String[] args) {
int numItems = 100;
LeftistHeap<Integer> h = new LeftistHeap<>( );
LeftistHeap<Integer> h1 = new LeftistHeap<>( );
int i = 37;
for( i = 37; i != 0; i = ( i + 37 ) % numItems )
if( i % 2 == 0 )
h1.insert( i );
else
h.insert( i );
h.merge( h1 );
for( i = 1; i < numItems; i++ )
if( h.deleteMin( ) != i )
System.out.println( "Oops! " + i );
}
}