一、定义:
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 );
}
}