算法导论 13-4 Treap树

来源:互联网 发布:北京淘宝视觉营销 编辑:程序博客网 时间:2024/06/15 19:32

题目


前言

   treap(树堆)具有二叉查找树和二叉堆的性质,按查找树的性质插入,再按堆的性质调整,也可以达到比较平衡的结果,而且实现比红黑树简单很多。


习题解答

(a) 由于关键字key互异,则该treap中序遍历唯一;又由于优先级priority互异,则对于每一棵树,根是确定的,因而前序遍历也是唯一的。中序遍历和前序遍历可以决定一棵树,由于它们的唯一性,因而决定的树也是唯一的。


(b) 根据堆的性质,可知treap高度为O(lgn);根据查找树的性质,可知查找时间与高度成正比,故为O(lgn)。


(c) 流程如下:

    1、根据查找树性质在treap中查找,找到节点应当插入的地方;

    2、如果存在,则插入失败;否则在该处插入,设置好相应指针;

    3、再根据堆性质开始自底向上调整。如果优先级比父节点小,且为右孩子,则将父节点左旋;

    4、否则,将父节点右旋,不断这样,直到其优先级不再小于父节点或者已成为根为止,插入成功。

算法实现在稍后给出。


(d) 自顶向下的查找需要时间O(lgn),自底向上的调整也需要时间O(lgn),故总时间为O(lgn)。


(e) 根据归纳法证明。

   初始:节点插入在叶子位置,且没有必要调整,那么C+D = 0;

   假设:在进行的插入过程中总共进行了k次旋转,按照题意则有:C+D = k;

   推导:那么在第k+1次旋转(假设为左旋,父节点为y,其右孩子为x)时,通过观察可以知道,y成为了x的左孩子,而x原本的左子树则成为了y的右子树,因而x的左子树的右脊柱增加了1,即C+D = k + 1.得证。


(f) Xi,k = 1 => y是x左子树的右脊柱

           => priority[y] > priority[x] 且 key[y] < key[x],由于步步可逆,故得证。

   对于存在z使得key[y] < key[z] < key[x],根据treap的性质可知,z必在y的右子树中,则priority[z] > priority[y].得证。


(g) 由于关键字连续 => 关键字k和i之间有k - i + 1个数

                => 排列方式总共有(k-i+1)!种,又因为能够构成y是x的左子树的右脊柱的排列方式有(k-i+1-2)! = (k-i-1)!种(去掉x本身及其左孩子)

                => Pr{Xi,k} = (k-i-1)!/(k-i+1)! = 1/[(k-i+1)(k-i)]


(h) 设y是x的左孩子。可知i = key[y] = k-1,k-2......2,1,相对应的,C = 1,2.....k-1,即k-i = C。

因而有:E[C] = 1 - 1/k。


(i) Pr{Xk,i} = (i-k-1)!/(i-k+1)! = 1/[(i-k+1)(i-k)]

    i = key[y] = k+1,k+2.....n-1,n,相对应的,D = 1,2....n-1-k,即i-k = D.

因而有:E[D] = 1 - 1/(n-k+1).


(j) 旋转期望总次数为:E[C+D] = 1 - 1/k + 1 - 1/(n-k+1) < 2.


实现代码,注释详实

有些算法并没有予以实现,因为和二叉查找树的实现非常类似,因而只实现了必要的一些函数。

//treap数据结构#include<iostream>#include<assert.h>#include<random>using namespace std;template <typename Key,typename Value>struct node{//节点Key key;//键Value value;//值int priority;//优先级node *parent = nullptr;node *left = nullptr;node *right = nullptr;node(const Key &k,const Value &v, int p) :key(k), value(v),priority(p){}void print()const{cout << key << '\t' << value/* << '\t' << priority*/ << endl;}};template <typename Key,typename Value,class CompareKey = less<Key>,int MaxPri = 10000>class treap//MaxPri表示优先级范围,默认是1~10000{//treap结构public:typedef node<Key,Value>node;private:node *root;CompareKey compare;void destroy(node*);//销毁treapvoid leftRotate(node*, node*);//左旋void rightRotate(node*, node*);//右旋void insertFixup(node*);//插入后调整void eraseFixup(node*);//删除后调整node* successor(node*)const;//求后继int getRandomPriority()const;//取得一个随机优先级public:treap() :root(nullptr){}treap(node *r) :root(r){}bool empty()const { return root == nullptr; }bool insert(const Key&,const Value&);bool erase(const Key&);bool edit(const Key&, const Value&);node* locate(const Key&)const;void inTraversal()const;void levelTraversal()const;//层次遍历void clear(){destroy(root);root = nullptr;}};template <typename Key,typename Value,class CompareKey = less<Key>,int MaxPri = 10000>void treap<Key,Value,CompareKey,MaxPri>::leftRotate(node *x, node *y){//x绕着y左旋转assert(x != nullptr && y != nullptr);y->parent = x->parent;if (x->parent != nullptr){//更新x的父节点的孩子if (x->parent->left == x)x->parent->left = y;else x->parent->right = y;}x->right = y->left;if (y->left != nullptr)y->left->parent = x;y->left = x;x->parent = y;}template <typename Key,typename Value,class CompareKey = less<Key>,int MaxPri = 10000>void treap<Key,Value,CompareKey,MaxPri>::rightRotate(node *y, node *x){//y绕着x右旋assert(y != nullptr && x != nullptr);x->parent = y->parent;if (y->parent != nullptr){//更新y的父节点的孩子if (y == y->parent->left)y->parent->left = x;else y->parent->right = x;}y->left = x->right;if (x->right != nullptr)x->right->parent = y;x->right = y;y->parent = x;}template <typename Key,typename Value,class CompareKey = less<Key>,int MaxPri = 10000>void treap<Key,Value,CompareKey,MaxPri>::insertFixup(node *curr){//插入后调整node *par = curr->parent;while (par != nullptr && curr->priority < par->priority){//如果未到根节点且当前节点的优先级比父节点小if (curr == par->right)//若是右孩子leftRotate(par, curr);//则左旋else rightRotate(par, curr);//否则右旋par = curr->parent;}if (par == nullptr) root = curr;}template <typename Key,typename Value,class CompareKey = less<Key>,int MaxPri = 10000>void treap<Key,Value,CompareKey,MaxPri>::eraseFixup(node *curr){//删除后调整node *p_min = curr;//找到三者中的优先级最小者if (curr->left != nullptr && curr->left->priority < p_min->priority)p_min = curr->left;if (curr->right != nullptr && curr->right->priority < p_min->priority)p_min = curr->right;if (p_min != curr){if (p_min == curr->left){//若左孩子优先级较小rightRotate(curr, p_min);//则右旋if (curr->right != nullptr)//然后以右孩子开始向上调整,因为右孩子有可能是第二小,这个过程也就是insertFixup//但是最多会调整一次insertFixup(curr->right);}else{//同上理leftRotate(curr, p_min);if (curr->left != nullptr)insertFixup(curr->left);}}}template <typename Key,typename Value,class CompareKey = less<Key>,int MaxPri = 10000>node<Key,Value>* treap<Key,Value,CompareKey,MaxPri>::successor(node *curr)const{//求后继if (curr->right != nullptr){//如果右子树不为空node *p = curr->right;while (p->left != nullptr)p = p->left;//则后继是右子树的最小值节点return p;}node *par = curr->parent;while (par != nullptr && curr == par->right){//否则,一直沿右侧向上,直到第一个拐弯处,即为后继curr = par;par = curr->parent;}return par;}template <typename Key,typename Value,class CompareKey = less<Key>,int MaxPri = 10000>void treap<Key,Value,CompareKey,MaxPri>::destroy(node *root){if (root == nullptr) return;if (root->left != nullptr)destroy(root->left);if (root->right != nullptr)destroy(root->right);delete root;}template <typename Key,typename Value,class CompareKey = less<Key>,int MaxPri = 10000>inline int treap<Key,Value,CompareKey,MaxPri>::getRandomPriority()const{random_device rd;//种子mt19937 gen(rd());//构造梅森旋转随机数生成器uniform_int_distribution<int> dist(1, MaxPri);//整数均匀分布范围return dist(gen);//获得一个随机数}template <typename Key,typename Value,class CompareKey = less<Key>,int MaxPri = 10000>bool treap<Key,Value,CompareKey,MaxPri>::insert(const Key &k,const Value &v){if (root == nullptr)//若插入的是第一个节点root = new node(k,v, getRandomPriority());else{node *curr = root,*par = nullptr;while (curr != nullptr){//找寻插入点par = curr;if (compare(k,curr->key))curr = curr->left;else curr = curr->right;}if (par->key == k) return false;//如果该关键字已经存在,则插入失败curr = new node(k, v,getRandomPriority());curr->parent = par;if (compare(k, par->key)) par->left = curr;else par->right = curr;insertFixup(curr);//调整}return true;}template <typename Key,typename Value,class CompareKey = less<Key>,int MaxPri = 10000>bool treap<Key,Value,CompareKey,MaxPri>::erase(const Key &k){//删除node *curr = locate(k);//定位删除节点if (curr == nullptr) return false;node *del, *child;if (curr->left == nullptr || curr->right == nullptr)//确定实际将被删除的节点del = curr;else del = successor(curr);if (del->left != nullptr)//记下被删节点的孩子child = del->left;else child = del->right;if (child != nullptr)child->parent = del->parent;//修改孩子父节点if (del == del->parent->left)//修改被删结点父母的孩子del->parent->left = child;else del->parent->right = child;if (del != curr){//复制数据curr->key = del->key;curr->priority = del->priority;eraseFixup(curr);//调整}delete del;return true;}template <typename Key, typename Value, class CompareKey, int MaxPri = 10000>bool treap<Key, Value, CompareKey, MaxPri>::edit(const Key &k, const Value &new_value){//修改某管子所关联的节点值node *curr = locate(k);//定位if (curr == nullptr) return false;//若不存在curr->value = new_value;return true;}template <typename Key,typename Value,class CompareKey,int MaxPri = 10000>node<Key,Value>* treap<Key, Value, CompareKey, MaxPri>::locate(const Key &k)const{//查找node *curr = root;while (curr != nullptr && !(!compare(k, curr->key) && !compare(curr->key, k))){//如果当前节点不是要找的节点if (compare(k, curr->key)) curr = curr->left;else curr = curr->right;//则继续迭代}return curr;}template <typename Key, typename Value, class CompareKey, int MaxPri = 10000>void treap<Key, Value, CompareKey, MaxPri>::inTraversal()const{if (root == nullptr) return;if (root->left != nullptr){treap L(root->left);L.inTraversal();}root->print();if (root->right != nullptr){treap R(root->right);R.inTraversal();}}template <typename Key, typename Value, class CompareKey, int MaxPri = 10000>void treap<Key, Value, CompareKey, MaxPri>::levelTraversal()const{//层次遍历解法3if (root == nullptr) return;root->print(); cout << endl;vector<node*> pvec;//利用一个数组(或者队列)存储已访问过的节点pvec.push_back(root);size_t curr = 0, last = 1;while (curr != pvec.size()){//只要数组中还存在元素size_t num = 0;//记录新添加的元素数for (; curr != last; ++curr){//遍历当前层的元素if (pvec[curr]->left != nullptr){//左孩子pvec[curr]->left->print();pvec.push_back(pvec[curr]->left);++num;}if (pvec[curr]->right != nullptr){//右孩子pvec[curr]->right->print();pvec.push_back(pvec[curr]->right);++num;}}cout << endl;last += num;}}#include<vector>int main(){/*treap<char, int> t;vector<char> cvec = { 'G', 'B', 'H', 'A', 'E', 'K', 'I' };vector<int> vec = { 1, 2, 3, 4, 5, 6, 7 };for (size_t i = 0; i != cvec.size(); ++i)t.insert(cvec[i], vec[i]);t.inTraversal();cout << "---------------------------" << endl;t.levelTraversal();t.insert('C', 25);t.insert('D', 9);t.insert('F', 2);cout << "---------------------------" << endl;t.inTraversal();cout << "---------------------------" << endl;t.levelTraversal();*///t.locate('C')->print();/*t.erase('C');t.erase('D');t.erase('F');*/treap<int, int> t;for (int i = 0; i != 100; ++i)t.insert(i, i * i);t.inTraversal();cout << "---------------------------" << endl;t.levelTraversal();t.clear();getchar();return 0;}




0 0
原创粉丝点击