Treap樹堆C++實現

Treap樹堆C++實現

Treap

  • Treap
    樹堆(Treap = Tree + Heap),指的是有一棵擁有鍵值、優先級兩種權值且滿足堆的性質的二叉搜索樹,其結構相當於以隨機數據插入的二叉搜索樹,若每個結點的優先級事先給定且互不相等,那麼整棵樹的形態也唯一確定,與元素插入順序無關,每個結點的優先級是隨機確定的,因此個操作的時間複雜度也隨機地,但插入、刪除、查找的期望時間複雜度均爲O(logn),其左右子樹也是Treap。通過使二叉搜索樹滿足堆的性質來儘量避免出現構造出單支樹(時間複雜度退化爲O(n))的情況,通過隨即優先級打破有序序列的構造序列
  • 算法思路
    Treap通過隨機地優先級和旋轉來維護Treap的性質,與平衡二叉樹不同的是,Treap只需要兩種旋轉方式,向左旋轉和向右旋轉

算法

旋轉

void Treap::leftRotate(Node* &p) {
    Node *k = p->right;
    p->right = k->left;
    k->left = p;
    p = k;
}

void Treap::rightRotate(Node* &p) {
    Node *k = p->left;
    p->left = k->right;
    k->right = p;
    p = k;
}
  • 思路
    基於結點p,向左旋轉時,指針k記錄當前結點的右子樹,將k的左子樹作爲結點p新的右子樹,將結點p作爲k的左子樹,最後使p指向結點k,結點p必須是結點指針的引用,以保證結點p的父結點的左右孩子被改變
  • 圖解

插入

void Treap::insert(Node* &p, int value) {
    if (p == NULL) {
        p = new Node(value, rand());
    } else {
        
        if (value == p->data) {
            return;
        } else if (value < p->data) {
            insert(p->left, value);
        } else {
            insert(p->right, value);
        }

        if(p->left && p->left->priority > p->priority) {
            rightRotate(p);
        } else if(p->right && p->right->priority < p->priority) {
            leftRotate(p);
        }
    }
}
  • 思路
    插入結點時,遞歸地,根據二叉搜索樹的性質找到結點應該插入的位置,產生一個隨機數作爲優先級,將結點插入Treap中,然後判斷是否需要旋轉,若當前子樹根節點的左子樹存在且優先級大於當前子樹優先級,則右旋轉,若當前子樹根節點的右子樹存在且優先級大於當前子樹優先級,則左旋轉,使得Treap維持堆的性質

刪除

  • 思路
    遞歸地,根據二叉搜索樹的性質找到待刪除結點的位置,爲維護Treap保持堆的性質(優先級保持堆的性質,關鍵字保持二叉搜索樹的性質),分爲三種情況
  1. 待刪除結點爲葉節點
    直接刪除
  2. 待刪除結點爲葉節點有且僅有一棵子樹
    將其子樹代替待刪除結點爲葉節點即可
  3. 待刪除結點爲葉節點有兩棵子樹
    兩棵子樹中優先級級高的旋轉到根結點,然後遞歸地在另一棵子樹中(待刪除節點作爲原子樹根已經旋轉到另一個子樹)刪除待刪除節點
  • 圖解
    結點外的值爲優先級

查找

  • 思路
    根據二叉搜索樹性質搜索即可

實現代碼

  • 實現中爲了看到效果,在類中增加了一個成員函數用於返回Treap中的最小值
/** @Author: eclipse 
 * @Email: [email protected] 
 * @Date: 2020-05-22 16:19:08 
 * @Last Modified by: eclipse
 * @Last Modified time: 2020-05-22 19:46:08
 */
#include<bits/stdc++.h>
using namespace std;

struct Node {
    int data;
    Node *left;
    Node *right;
    int priority;
    Node(int value, int level) : data(value), left(NULL), right(NULL), priority(level) {}
};

class Treap {
private:
    Node *root;
    void leftRotate(Node* &p);
    void rightRotate(Node* &p);
    void insert(Node* &p, int value);
    void remove(Node* &p, int value);
public:
    Treap();
    void insert(int value);
    void remove(int x);
    bool search(int x);
    int smallest();
};

Treap::Treap() {
    root = NULL;
}

void Treap::leftRotate(Node* &p) {
    Node *k = p->right;
    p->right = k->left;
    k->left = p;
    p = k;
}

void Treap::rightRotate(Node* &p) {
    Node *k = p->left;
    p->left = k->right;
    k->right = p;
    p = k;
}

void Treap::insert(int value) {
    insert(root, value);
}

void Treap::insert(Node* &p, int value) {
    if (p == NULL) {
        p = new Node(value, rand());
    } else {
        
        if (value == p->data) {
            return;
        } else if (value < p->data) {
            insert(p->left, value);
        } else {
            insert(p->right, value);
        }

        if(p->left && p->left->priority > p->priority) {
            rightRotate(p);
        } else if(p->right && p->right->priority < p->priority) {
            leftRotate(p);
        }
    }
}

void Treap::remove(int value) {
    remove(root, value);
}

void Treap::remove(Node* &p, int value) {
    if (p->data == value) {
        if (p->left == NULL) {
            p = p->right;
        } else if (p->right == NULL) {
            p = p->left;
        } else {
            if (p->left->priority > p->right->priority) {
                rightRotate(p);
                remove(p->right, value);
            } else if (p->left->priority < p->right->priority) {
                leftRotate(p);
                remove(p->left, value);
            }
        }
    } else {
        if (value < p->data) {
            remove(p->left, value);
        } else {
            remove(p->right, value);
        }
    }
}

bool Treap::search(int value) {
    Node *p = root;
    while (p) {
        if (p->data == value) {
            return true;
        } else {
            p = p->data < value ? p->right : p->right;
        }
    }
    return false;
}

int Treap::smallest() {
    Node* p = root;
    int value;
    while (p) {
        value = p->data;
        p = p->left;
    }
    return value;
}

int main(int argc, char const *argv[]) {
    Treap treap;
    int N;
    scanf("%d", &N);
    for (int i = 0; i < N; i++) {
        int value;
        scanf("%d", &value);
        treap.insert(value);
    }
    for (int i = 0; i < N; i++) {
        int value = treap.smallest();
        printf("%d ", value);
        treap.remove(value);
    }
    return 0;
}

輸入數據

10
20 19 28 34 123 8900 21334 4345 234 567

輸出數據

19 20 28 34 123 234 567 4345 8900 21334

鳴謝

《算法競賽入門經典訓練指南》

最後

  • 由於博主水平有限,不免有疏漏之處,歡迎讀者隨時批評指正,以免造成不必要的誤解!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章