二叉搜索树及其代码实现

二叉搜索树(BST)

它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树

性质:中序遍历为升序

such as:

它支持:插入,查询,删除

在接下来的说明中,我们认为元素没有重复(有的话就记录出现次数cnt就好了)

插入:

当我们插入一个数时,和根节点比较大小,如果比根节点小就到左子树寻找,否则到右子树寻找,然后重复上述过程,直到找到插入的位置

例如:插入15

1.和13比较,15>13,向右子树寻找

2.和16比较,15<16,向左子树寻找

3.和14比较,15>14,向右子树寻找,右子树为空,则节点15插入到14的右边

查询

设数组(siz[x])表示以(x)为根节点的子树的大小(包括(x)),(ls)表示当前节点的左儿子,(rs)表示当前节点的右儿子

查询(x)的排名:比较(x)与根节点的大小,如果等于根节点,排名为(siz[ls]+1);如果比根节点小,到左子树中查找,排名为左子树的排名;如果比根节点大,到右子树中查找,排名为右子树的排名+siz[ls]+1

查询排名为(x)的数:判断左子树大小和(x)的关系。如果(siz[ls]+1=x),说明根节点就是要找的x;否则,如果siz[ls]>x,说明这个数在左子树中,到左子树寻找排名为x的数;如果siz[ls]<x,说明这个数在右子树中,到右子树寻找排名为x-siz[ls]-1的数

查询x的前驱:先查找到x的位置,然后找到左子树最靠右的儿子

查询x的后继:先查找到x的位置,然后找到右子树最靠左的儿子

删除

定位当前节点。如果左子树为空,就把右子树提上来,如果右子树为空,就把左子树提上来。否则,删去右子树最小的节点(这个节点的左子树一定为空),把这个节点移动到当前节点的位置上来。

#include<bits/stdc++.h>
using namespace std;
const int N = 100005;

int n, cnt, rot;

struct node
{
	int ls, rs, val, siz, cnt;
}nod[N];

void Push_up(int x)
{
	int ls = nod[x].ls, rs = nod[x].rs;
	nod[x].siz = nod[ls].siz + nod[rs].siz + nod[x].cnt;
} 

void Insert(int &rt, int x)
{
	if(rt == 0)
	{
		rt = ++cnt;
		nod[rt].siz = nod[rt].cnt = 1;
		nod[rt].val = x;
		return;
	}
	if(nod[rt].val == x)
	{
		nod[rt].cnt ++;
		nod[rt].siz ++;
		return;
	}
	if(nod[rt].val < x)
	{
		Insert(nod[rt].rs, x);
		Push_up(rt);
		return;
	}
	if(nod[rt].val > x)
	{
		Insert(nod[rt].ls, x);
		Push_up(rt);
		return;
	}
}

int Findmin(int &rt)
{
	if(nod[rt].ls)
	{
		int ret = Findmin(nod[rt].ls);
		Push_up(rt);
		return ret;
	}
	int ret = rt;
	rt = nod[rt].rs;
	return ret; 
}

void Delete(int &rt, int x)
{
	if(nod[rt].val == x)
	{
		if(nod[rt].cnt > 1) 
		{
			nod[rt].cnt --;
			nod[rt].siz --;
			return;
		}
		else
		{
			if(nod[rt].ls == 0)
			{
				rt = nod[rt].rs;
				return;
			}
			if(nod[rt].rs == 0)
			{
				rt = nod[rt].ls;
				return;
			}
			else
			{
				int nd = Findmin(nod[rt].rs);
				nod[rt].val = nod[nd].val;
				nod[rt].cnt = nod[nd].cnt;
				Push_up(rt);
				return;
			}
		}
	}
	if(nod[rt].val < x)
	{
		Delete(nod[rt].rs, x);
		Push_up(rt);
		return;
	}
	if(nod[rt].val > x)
	{
		Delete(nod[rt].ls, x);
		Push_up(rt);
		return;
	}
}

int Getk(int rt, int x)
{
	if(nod[rt].val == x) return nod[nod[rt].ls].siz + 1;
	else if(nod[rt].val < x) return nod[nod[rt].ls].siz + nod[rt].cnt + Getk(nod[rt].rs, x);
	else if(nod[rt].val > x) return Getk(nod[rt].ls, x);
}

int Getkth(int rt, int x)
{
	if(nod[nod[rt].ls].siz + 1 <= x && nod[nod[rt].ls].siz + nod[rt].cnt >= x) return nod[rt].val;
	if(nod[nod[rt].ls].siz + 1 > x) return Getkth(nod[rt].ls, x);
	if(nod[nod[rt].ls].siz + nod[rt].cnt < x) return Getkth(nod[rt].rs, x - (nod[nod[rt].ls].siz + nod[rt].cnt));
}

int Getpre(int rt, int x)
{
	int p = rt, ans;
	while(p)
	{
		if(x <= nod[p].val) p = nod[p].ls;
		else ans = p, p = nod[p].rs;
	}
	return nod[ans].val;
}

int Getsuc(int rt, int x)//succeed
{
	int p = rt, ans;
	while(p)
	{
		if(x >= nod[p].val) p = nod[p].rs;
		else ans = p, p = nod[p].ls;
	}
	return nod[ans].val;
}

int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++)
	{
		int opt, x;
		scanf("%d%d", &opt, &x);
		if(opt == 1) Insert(rot, x);
		if(opt == 2) Delete(rot, x);
		if(opt == 3) printf("%d
", Getk(rot, x));
		if(opt == 4) printf("%d
", Getkth(rot, x));
		if(opt == 5) printf("%d
", Getpre(rot, x));
		if(opt == 6) printf("%d
", Getsuc(rot, x));
	}
}

下一篇:朝鲜树

原文地址:https://www.cnblogs.com/lcezych/p/12241035.html