Java資料結構與演算法解析(十七)——斜堆__儲存

來源:互聯網
上載者:User
                   Java資料結構與演算法解析(十七)——斜堆 斜堆概述

斜堆(Skew heap)也叫自適應堆(self-adjusting heap),它是左斜堆的一個變種。和左傾堆一樣,它通常也用於實現優先隊列;作為一種自適應的左斜堆,它的合併作業的時間複雜度也是O(lg n)。 
它與左斜堆的差別是: 
(1) 斜堆的節點沒有”零距離”這個屬性,而左斜堆則有。 
(2) 斜堆的合併作業和左傾堆的合併作業演算法不同。 
斜堆的合併作業

(1) 如果一個空斜堆與一個非空斜堆合并,返回非空斜堆。 
(2) 如果兩個斜堆都非空,那麼比較兩個根節點,取較小堆的根節點為新的根節點。將”較小堆的根節點的右孩子”和”較大堆”進行合并。 
(3) 合并後,交換新堆根節點的左孩子和右孩子。 
第(3)步是斜堆和左傾堆的合併作業差別的關鍵所在,如果是左傾堆,則合并後要比較左右孩子的零距離大小,若右孩子的零距離 > 左孩子的零距離,則交換左右孩子;最後,在設定根的零距離。

由於合并都是沿著最右路徑進行的,經過合并之後,新斜堆的最右路徑長度必然增加,這會影響下一次合并的效率。所以合并後,通過交換左右子樹,使整棵樹的最右路徑長度非常小(這是啟發規則)。然而斜堆不記錄節點的距離,在操作時,從下往上,沿著合并的路徑,在每個節點處都交換左右子樹。通過不斷交換左右子樹,斜堆把最右路徑甩向左邊了。

遞迴實現合并

1.比較兩個堆; 設p是具有更小的root的索引值的堆,q是另一個堆,r是合併後的結果堆。 
2.令r的root是p(具有最小root索引值),r的右子樹為p的左子樹。 
3.令r的左子樹為p的右子樹與q合併的結果。

合并前: 

合并後: 

非遞迴合并實現

1.把每個堆的每棵(遞迴意義下)最右子樹切下來。這使得得到的每棵樹的右子樹均為空白。 
2.按root的索引值的升序排列這些樹。 
3.迭代合併具有最大root索引值的兩棵樹: 
1)具有次大root索引值的樹的右子樹必定為空白。把其左子樹與右子樹 
2)交換。現在該樹的左子樹為空白。 
具有最大root索引值的樹作為具有次大root索引值樹的左子樹。 
效能比較

斜堆的代碼實現 1. 基本定義

public class SkewHeap<T extends Comparable<T>>  {    private SkewNode<T> mRoot;    // 根結點    private class SkewNode<T extends Comparable<T>> {        T key;                // 關鍵字(索引值)        SkewNode<T> left;    // 左孩子        SkewNode<T> right;    // 右孩子        public SkewNode(T key, SkewNode<T> left, SkewNode<T> right) {            this.key = key;            this.left = left;            this.right = right;        }        public String toString() {            return "key:"+key;        }    }}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

SkewNode是斜堆對應的節點類。 
SkewHeap是斜堆類,它包含了斜堆的根節點,以及斜堆的操作。 2. 合并

/* * 合并"斜堆x"和"斜堆y" */private SkewNode<T> merge(SkewNode<T> x, SkewNode<T> y) {    if(x == null) return y;    if(y == null) return x;    // 合并x和y時,將x作為合并後的樹的根;    // 這裡的操作是保證: x的key < y的key    if(x.key.compareTo(y.key) > 0) {        SkewNode<T> tmp = x;        x = y;        y = tmp;    }    // 將x的右孩子和y合并,    // 合并後直接交換x的左右孩子,而不需要像左傾堆一樣考慮它們的npl。    SkewNode<T> tmp = merge(x.right, y);    x.right = x.left;    x.left = tmp;    return x;}public void merge(SkewHeap<T> other) {    this.mRoot = merge(this.mRoot, other.mRoot);}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

merge(x, y)是內部介面,作用是合并x和y這兩個斜堆,並返回得到的新堆的根節點。 
merge(other)是外部介面,作用是將other合并到當前堆中。 3. 添加

/*  * 建立結點(key),並將其插入到斜堆中 * * 參數說明: *     key 插入結點的索引值 */public void insert(T key) {    SkewNode<T> node = new SkewNode<T>(key,null,null);    // 如果建立結點失敗,則返回。    if (node != null)        this.mRoot = merge(this.mRoot, node);}
1 2 3 4 5 6 7 8 9 10 11 12 13

insert(key)的作用是建立索引值為key的節點,並將其加入到當前斜堆中。 4. 刪除

/*  * 刪除根結點 *  * 傳回值: *     返回被刪除的節點的索引值 */public T remove() {    if (this.mRoot == null)        return null;    T key = this.mRoot.key;    SkewNode<T> l = this.mRoot.left;    SkewNode<T> r = this.mRoot.right;    this.mRoot = null;          // 刪除根節點    this.mRoot = merge(l, r);   // 合并左右子樹    return key;}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

remove()的作用是刪除斜堆的最小節點。 完整代碼

public class SkewHeap<T extends Comparable<T>> {    private SkewNode<T> mRoot;    // 根結點    private class SkewNode<T extends Comparable<T>> {        T key;                // 關鍵字(索引值)        SkewNode<T> left;    // 左孩子        SkewNode<T> right;    // 右孩子        public SkewNode(T key, SkewNode<T> left, SkewNode<T> right) {            this.key = key;            this.left = left;            this.right = right;        }        public String toString() {            return "key:"+key;        }    }    public SkewHeap() {        mRoot = null;    }    /*     * 前序走訪"斜堆"     */    private void preOrder(SkewNode<T> heap) {        if(heap != null) {            System.out.print(heap.key+" ");            preOrder(heap.left);            preOrder(heap.right);        }    }    public void preOrder() {        preOrder(mRoot);    }    /*     * 中序遍曆"斜堆"     */    private void inOrder(SkewNode<T> heap) {        if(heap != null) {            inOrder(heap.left);            System.out.print(heap.key+" ");            inOrder(heap.right);        }    }    public void inOrder() {        inOrder(mRoot);    }    /*     * 後序遍曆"斜堆"     */    private void postOrder(SkewNode<T> heap) {        if(heap != null)        {            postOrder(heap.left);            postOrder(heap.right);            System.out.print(heap.key+" ");        }    }    public void postOrder() {        postOrder(mRoot);    }    /*     * 合并"斜堆x"和"斜堆y"     */    private SkewNode<T> merge(SkewNode<T&

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.