「笔记」二叉搜索树
定义及性质 :
- 一棵带点权的 二叉树 .
- 左子树上所有结点 均小于 根节点.
- 右子树上所有结点 均大于 根节点.
- 左右子树 也满足上述性质.
\[\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 实现
作者@Luckyblock,转载请声明出处。