「笔记」二叉搜索树


定义及性质 :

  • 一棵带点权的 二叉树 .
  • 左子树上所有结点 均小于 根节点.
  • 右子树上所有结点 均大于 根节点.
  • 左右子树 也满足上述性质.
匹配

\[\text{形态} \]


功能:

一般的二叉搜索树支持下列功能 :

  • 指定元素的 插入, 删除.
  • 查询 某元素是否属于集合, 最大值, 最小值, 前驱, 后继.
  • 集合的有序遍历.
  • \(\dots\)

暴力实现

注:代码未经过压力测试,可能含有部分bug。

//知识点:二叉搜索树 
/*
By:Luckyblock
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
#define ll long long
const int MARX = 1e5 + 10;
//===========================================================
struct BST
{
	int ls, rs, Val;
} Tree[MARX];
int M, Size, Root = 1;
//===========================================================
inline int read()
{
    int f = 1, w = 0; char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
    return f * w;
}
void Traverse(int now)
{
	if(Tree[now].ls) Traverse(Tree[now].ls);
	printf("%d ", Tree[now].Val);
	if(Tree[now].rs) Traverse(Tree[now].rs);
}
bool Search(int now, int Val)
{
	if(! now) return false;
	if(Val == Tree[now].Val) return true;
	if(Val < Tree[now].Val) return Search(Tree[now].ls, Val);
	return Search(Tree[now].rs, Val);
}
int SearchMax(int now)
{
	if(! Tree[now].rs) return Tree[now].Val;
	return SearchMax(Tree[now].rs);
}
int SearchMin(int now)
{
	if(! Tree[now].ls) return Tree[now].Val;
	return SearchMin(Tree[now].ls);
}
void Insert(int &now, int Val)
{
	if(! Size) {Tree[++ Size].Val = Val; return ;}
	if(! now) now = ++ Size, Tree[now].Val = Val;
	else if(Val <= Tree[now].Val) Insert(Tree[now].ls, Val);
	else if(Val > Tree[now].Val) Insert(Tree[now].rs, Val);
}
int DeleteMin(int &now)
{
	if(! Tree[now].ls)
	{
	  int tmp = Tree[now].Val;
	  if(now != Root) now = Tree[now].rs;
	  Size --; 
	  return tmp;
	}
	else return DeleteMin(Tree[now].ls);
}
void Delete(int &now, int Val)
{
	if(Tree[now].Val == Val)
	{
	  if(Tree[now].ls && Tree[now].rs) Tree[now].Val = DeleteMin(Tree[now].rs);
	  else now = Tree[now].ls + Tree[now].rs;
	  Size --;
	  return ;
	}
	if(Tree[now].Val > Val) Delete(Tree[now].ls, Val);
	else Delete(Tree[now].rs, Val);
}
//===========================================================
int main()
{
	M = read();
	for(int i = 1; i <= M; i ++)
	{
	  int opt = read(), Val;
	  if(opt < 5)
	  {
	  	if(! Size) {putchar('No'); putchar('\n'); continue;}
	    if(opt == 1) Traverse(1), putchar('\n'); //遍历二叉查找树. 
	    if(opt == 2) Val = read(), printf("%c\n", Search(1, Val) ? 'Y' : 'N'); //判断Val是否存在于集合中 
	    if(opt == 3) printf("%d\n", SearchMax(1)); //查询最大值 
	    if(opt == 4) printf("%d\n", SearchMin(1)); //查询最小值 
	  }
	  if(opt == 5) Val = read(), Insert(Root, Val); //插入Val 
	  if(opt == 6) Val = read(), Delete(Root, Val); //删除Val 
	  if(opt == 7) DeleteMin(Root); //删除最小值 
	  if(opt == 8) Val = read(), 
	}
    return 0;
}

问题

可发现暴力实现法存在一定弊端。
当树呈链式时,单次插入,查询操作的复杂度将变为 \(O(n)\) 级别。
程序的总复杂度将达到 \(O(n^2)\) 级别。

因此通常使用Splay,Treap等进行二叉搜索树的实现。

Splay 实现

FHQ-Treap实现

旋转Treap 实现

posted @ 2020-04-28 08:45  Luckyblock  阅读(204)  评论(1编辑  收藏  举报