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

鸣谢

《算法竞赛入门经典训练指南》

最后

  • 由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章