優先隊列之左式堆(JAVA實現)

一、定義:

1.零路徑長度:某節點的零路徑長度爲該節點到沒有兩個兒子的節點最短距離。

2.左式堆性質:

  • 父節點屬性值小於子節點屬性值;
  • 堆中的任何節點,其左兒子的零路徑長>=右兒子的零路徑長的二叉樹。
  • 任一結點的零路徑長比他的諸兒子結點的零路徑長的最小值多1。

二、實現思路:

1.合併:
左式堆的合併操作基於遞歸實現,算法思路如下:

  1. 若有一棵樹是空樹,則返回另一棵樹;否則將根節點較大的堆與根節點較小的堆的右子樹合併。
  2. 使形成的新堆作爲較小堆的右子樹。
  3. 如果違反了左式堆的特性,交換兩個子樹的位置。
  4. 更新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 );
    }
}

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