BST升级 I - Treap树堆

前面写了BST。而Treap是一种简单好写的动态平衡BST,。


Treap = Tree + heap,树堆

Treap是一个有值(value)优先级(priority)的树。看value,Treap是BST;看priority,Treap是堆。这里写的是大根堆,即每个结点的优先级大于它的孩子.


下面是一些操作。

#旋转:有点难理解,下面是我的总结的旋转过程

当前结点要旋转的结点为k,左孩子是k.l,右孩子是k.r

左旋:右子树换成k.r的左子树,k父亲改成k.r

右旋:左子树换成k.l的右子树,k父亲改成k.l

左旋右旋完全相反,互为逆操作。


上个图,不然容易晕眩而且看不懂的



#插入:先随机赋给新节点一个priority,然后用BST的插入方法插入。然后再往上走,根据优先级维护堆的性质,不满足就旋转

生成随机数?当然是rand()函数;


#删除:理解插入以后,删除也不难,过程相反。

先找到结点,如果只有一棵子树,直接把子树结点接到父亲上。如果有两棵,把优先级高的旋上来,再递归删除这个结点.


同样封装到struct Treap里了。

    

struct Treap {
	struct Node {
		Node * ch[2];
		int priority, value;
		int cmp(int x) {
			if(x == value) return -1;
			return x > value;
		}
	};
	void rotate(Node* &o, int d) { //d=0左旋
		Node *k = o->ch[d^1];  //d^1相当于1-d
		o->ch[d^1] = k->ch[d];
		k->ch[d] = o;
		o = k;
	}
	void insert(Node* &o, int x) {
		if(o == NULL) {
			o = new Node();
			o -> ch[0] = o -> ch[1] = NULL;
			o -> value = x;
			o -> priority = rand();
		} else {
			int d = o->cmp(x);
			insert(o->ch[d], x);
			if(o->ch[d] -> priority > o->priority)
				rotate(o, d^1);
		}
	}
	void remove(Node* &o, int x) {
		int d = o->cmp(x);
		if(d == -1) {
			if(o->ch[0] == NULL) o = o->ch[1];
			else if(o->ch[1] == NULL) o = o->ch[0];
			else {
				int d2 = (o->ch[0]->priority > o->ch[1]->priority);
				rotate(o, d2);
				remove(o->ch[d2], x);
			}
		}
	}
	bool find(Node* &o, int x) {
		while(o != NULL) {
			int d = o -> cmp(x);
			if(d == -1) return true;
			o = o->ch[d];
		}
		return false;
	}
};


Treap的功能还有-名次树(Rank Tree)

每个结点多一个sz值,表示以它为根的树结点数.



#Rank x: 查找值为x的名次

rk初始化为左子树大小

if x在左子树 在左子树查找

if x为当前结点 答案为rk+1

else 返回rk+ 当前结点cnt + 右子树查找rank

#Kth k:查找名字为k的值

sz初始化为左子树大小

if k<=sz 在左子树查找

else if k在sz+1和sz+cnt之间,说明找的是此结点,返回当前结点value

else 返回右子树找k-sz-cnt名.


这两个都不难,很容易实现

之前没有介绍,Treap每个结点不允许有value重复,因此每个结点再加一个值叫cnt(初始化=1),记录出现次数.


看下Treap洛谷原题

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

struct Treap_Rank_Tree {
	struct Node {
		Node * ch[2];
		int priority, value, cnt, sz;
		Node(int v) : value(v) {sz = 1; cnt = 1; priority = rand(); ch[0] = ch[1] = NULL;}
		int cmp(int x) {
			if(x == value) return -1;
			return x > value;
		}
		void maintain() {
			sz = cnt;
			if(ch[0] != NULL) sz += ch[0]->sz;
			if(ch[1] != NULL) sz += ch[1]->sz;
		}
	};
	Node *Root;
	Treap_Rank_Tree() {
		Root = NULL;
	}
	void rotate(Node* &o, int d) {
		Node *k = o->ch[d^1];
		o->ch[d^1] = k->ch[d];
		k->ch[d] = o;
		o->maintain();
		k->maintain();
		o = k;
	}
	void insert(Node* &o, int x) {
		if(o == NULL) o = new Node(x);
		else {
			int d = o->cmp(x);
			if(d == -1) {
				o->cnt ++;
				o->sz ++;
				return;
			}
			insert(o->ch[d], x);
			if(o->ch[d] -> priority > o->priority)
				rotate(o, d^1);
			o -> maintain();
		}
	}
	void remove(Node* &o, int x) {
		if(o == NULL) return;
		int d = o->cmp(x);
		if(d == -1) {
			if(o->cnt > 1) {
				o->cnt --;
				o->sz --;
				return;
			}
			if(o->ch[0] == NULL) o = o->ch[1];
			else if(o->ch[1] == NULL) o = o->ch[0];
			else {
				int d2 = (o->ch[0]->priority < o->ch[1]->priority);
				rotate(o, d2);
				remove(o->ch[d2], x);
			}
		} else remove(o->ch[d], x);
		if(o != NULL)	o -> maintain();
	}
	bool find(Node* &o, int x) {
		while(o != NULL) {
			int d = o -> cmp(x);
			if(d == -1) return true;
			o = o->ch[d];
		}
		return false;
	}
	int Rank(Node* o, int x) {
		int rk = 0;
		if(o->ch[0] != NULL) rk = o->ch[0]->sz;
		if(x < o->value) return Rank(o->ch[0], x);
		if(x == o->value) return rk+1;
		return rk + o->cnt + Rank(o->ch[1], x);
	}
	int Kth(Node* o, int k) {
		int sz = 0;
		if(o->ch[0] != NULL) sz = o->ch[0]->sz;
		if(k <= sz) return Kth(o->ch[0], k);
		else if(k <= sz + o->cnt) return o->value;
		return Kth(o->ch[1], k-sz-(o->cnt));
	}
	int _Find_1(Node* o, int x) { //找前驱
		if(o == NULL) return -2e9;
		if(o->value < x) return max(o->value, _Find_1(o->ch[1], x));
		else return _Find_1(o->ch[0], x);
	}
	int _Find_2(Node* o, int x) { //找后继
		if(o == NULL) return 2e9;
		if(o->value > x) return min(o->value, _Find_2(o->ch[0], x));
		else return _Find_2(o->ch[1], x);
	}
} treap;

int main() {
	srand(time(NULL));
	int Q, opt, x;
	cin >> Q;
	for(int i=1; i<=Q; i++) {
		cin >> opt >> x;
		if(opt == 1) treap.insert(treap.Root, x);
		else if(opt == 2) treap.remove(treap.Root, x);
		else if(opt == 3) cout << treap.Rank(treap.Root, x) << endl;
		else if(opt == 4) cout << treap.Kth(treap.Root, x) << endl;
		else if(opt == 5) cout << treap._Find_1(treap.Root, x) << endl;
		else if(opt == 6) cout << treap._Find_2(treap.Root, x) << endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Binary_Heap/article/details/79313229
今日推荐