• 二叉搜索树及其代码实现


    二叉搜索树(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));
    	}
    }
    

    下一篇:朝鲜树

  • 相关阅读:
    输入和输出

    4. 深入 Python 流程控制
    js下拉框选择图片
    按下enter触发事件
    js多种方法取数组的最后一个元素
    apply,call,bind函数作用与用法
    vue中的js绑定样式
    js添加删除class
    rem等比例自适应手机尺寸
  • 原文地址:https://www.cnblogs.com/lcezych/p/12241035.html
Copyright © 2020-2023  润新知