BST
BST即为binarysearch tree 二叉搜索树为平衡树的基础,所以很要学习的必要。
BST的结点满足一个基本条件就是:结点k的左子树中所有值小于结点k的值,结点k的右子树的所有值大于结点k的值,显然这是一个递归定义的结构。
这个结构就使得中序遍历出来的序列即是一个升序的序列。一个优秀的二叉搜索树能够在log(n)的时间内进行查找、删除一个元素等。
在这里我没有使用指针。当然指针版的更为方便好用。
首先是建树的过程,因为在这里没有使用指针,所以用0来表示空结点,1表示root结点。建树为递归过程。
插入和查找操作两者相似,且比较简单。唯一复杂点的操作就是删除操作。下面分几种情况来讨论:
1. 需要删除的结点为叶子结点,即此结点没有左儿子和右儿子。直接将此结点的父亲结点的信息更新为不指向此结点即可。
2. 需要删除的结点只有一个儿子,左儿子或者右儿子。对于只有左儿子的情况,只需要将左儿子的父亲更新为此结点的父亲,同时更新此结点父亲的指向。右儿子类似。
3. 需要删除的结点既有左儿子又有右儿子。这种情况稍微麻烦一点,可考虑将右子树中最小值赋值给待删结点,这样保证了树的结构,然后再将右子树中最小值结点按叶子结点,即情况1的方法删除。这里还涉及了查询最小值操作。
/**********************************************
随机化二叉搜索树 插入 查找 删除 操作 非指针版
***********************************************/
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<time.h>
#define rep(i,n) for(int i=0;i<n;i++)
#define rrep(i,n) for(int i=1;i<=n;i++)
using namespace std;
struct TreeNode
{
int key,freq;//frep纪录此值出现的次数
int lson,rson,fa;
};
const int maxn=10100;
TreeNode tree[maxn];
int A[maxn];
int root=1,n,m,x,tot;//root为1 空结点用0表示
//插入操作
void insert(int k,int x)
{
if(tree[k].freq==0){
tree[k].key=x;
tree[k].freq=1;
return;
}
if(x==tree[k].key){
tree[k].freq++;
return;
}
//插入为左儿子
if((x<tree[k].key)&&(tree[tree[k].lson].freq==0)){
tot++;
tree[k].lson=tot;
tree[tot].freq=1;
tree[tot].key=x;
tree[tot].freq=1;
tree[tot].fa=k;
return;
}
//插入为右儿子
if((x>tree[k].key)&&(tree[tree[k].rson].freq==0)){
tot++;
tree[k].rson=tot;
tree[tot].freq=1;
tree[tot].key=x;
tree[tot].freq=1;
tree[tot].fa=k;
return;
}
if(x<tree[k].key)insert(tree[k].lson,x);
else insert(tree[k].rson,x);
}
//查找最小值
int searchmin(int k)
{
if(tree[k].lson==0)return tree[k].key;
return searchmin(tree[k].lson);
}
//查找最大值
int searchmax(int k)
{
if(tree[k].rson==0)return tree[k].key;
return searchmax(tree[k].rson);
}
bool del(int k,int x)
{
if(tree[k].freq==0)return 0;
if(x<tree[k].key){return del(tree[k].lson,x);}
if(x>tree[k].key){return del(tree[k].rson,x);}
// if(tree[k].freq>1){tree[k].freq--;return 1;}//一个值出现了多次
//叶子结点 直接删除
if((tree[k].lson==0)&&(tree[k].rson==0)){
tree[k].freq=0;
int fa=tree[k].fa;
if(tree[k].key<tree[fa].key) tree[fa].lson=0;
else tree[fa].rson=0;
tree[k].key=0;
return 1;
}
//只有左儿子或者右儿子
if(((tree[k].lson==0)&&(tree[k].rson!=0))||((tree[k].lson!=0)&&(tree[k].rson==0))){
//只有左儿子
if(tree[k].lson){
int fa=tree[k].fa;
if(tree[k].key<tree[fa].key)tree[fa].lson=tree[k].lson;
else tree[fa].rson=tree[k].lson;
tree[tree[k].lson].fa=fa;
tree[k].key=0;
tree[k].freq=0;
}
//只有右儿子
else{
int fa=tree[k].fa;
if(tree[k].key<tree[fa].key)tree[fa].lson=tree[k].rson;
else tree[fa].rson=tree[k].rson;
tree[tree[k].rson].fa=fa;
tree[k].key=0;
tree[k].freq=0;
}
return 1;
}
//既有左儿子又有右儿子 此时将右儿子中key最小的结点值来替换当前要删除的结点
int temp=searchmin(tree[k].rson);//查找右子树中最小值
tree[k].key=temp;
del(tree[k].rson,temp);
return 1;
}
//查询
bool query(int k,int x)
{
if(tree[k].freq==0)return 0;
if(tree[k].key==x)return 1;
if(x<tree[k].key)return query(tree[k].lson,x);
if(x>tree[k].key)return query(tree[k].rson,x);
}
//中序遍历输出 即为升序排列值(无重复元素)
void middle_order(int k)
{
if(tree[k].freq==0)return;
if(tree[k].lson)middle_order(tree[k].lson);
rep(i,tree[k].freq)printf("%d ",tree[k].key);//重复元素按重复次数输出
if(tree[k].rson)middle_order(tree[k].rson);
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&n);
tot=1;
rep(i,n)scanf("%d",&A[i]);
//随机化处理后 算法进行一次查询 删除等操作的平均时间为log(n) 大大优化了程序 在原始数据就是有序的情况下也能高效运行
srand(time(0));
int k=rand()%n;
swap(A[0],A[k]);
//插入操作
rep(i,n)insert(root,A[i]);
//删除操作
scanf("%d",&n);
rep(i,n){
scanf("%d",&x);
if(del(root,x))printf("Deleted %d\n",x);
else printf("Not Deleted\n");
}
//查询操作
scanf("%d",&n);
rep(i,n){
scanf("%d",&x);
if(query(root,x))printf("Yes\n");
else printf("No\n");
}
middle_order(root);//中序遍历 即为升序排序值
printf("%d\n",searchmin(root));//求最小值
printf("%d\n",searchmax(root));//求最大值
return 0;
}