算法笔记:二叉搜索树BST

专题:二叉搜索树BST

一、定义

        二叉搜索树(Binary Search Tree),也称有序二叉树或排序二叉树,是指一棵空树或者具有下列性质的二叉树:

        1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;

        2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;

        3. 任意节点的左、右子树也分别为二叉搜索树。

        也就是说:设x是二叉搜索树中的一个节点。

        如果y是x的左子树中的一个节点,则有y.key

        如果y是x的右子树中的一个节点,则有y.key>x.key。

二、结构与基本操作

1. 二叉搜索树具有很高的灵活性,对其优化可以生成平衡二叉树,红黑树等高效的查找和插入数据结构。

2. 基本操作:

(1)查找:查询是否包含某个数值

        该查找方法也叫“树表查找”。类似二分查找,将待查找数值val和当前节点的值key比较:

        若val=key,表示找到,返回该值或者找到的信息;

        若val

        若val>key,则往右儿子节点走,在右子树中继续查找。

(2)插入:向二叉搜索树中插入某个节点

        按照上述查找数值的方法试图查找这个数值的节点,就可以知道其对应的节点的所在位置,之后在那个位置插入新的节点即可。

        【该过程可分解为”查找->插入”两步】

(3)删除:向二叉搜索树中删除某个节点

        一般来说,需要根据下面几种情况分别进行处理:

        ①  需要删除的节点没有左儿子,那么就把右儿子提上去

        ②  需要删除的节点的左儿子没有右儿子,那么就把左儿子提上去

        ③  以上两种情况都不满足的话,就把左儿子的子孙中最大的节点提到需要删除的节点上。

        【该过程可分解为”查找->删除->调整”三步】

3. 一个特殊特性:对二叉搜索树进行中序遍历,可以得到节点值的有序序列。

三、复杂度分析

        不论以上哪种操作,所花的时间都和树的高度成正比。因此,如果共有n个元素,则平均每次操作需要O(logn)的时间。

四、代码实现

#include 
#include 
#define maxn 1010
int n;               //待插入BST的元素数
int elem[maxn];      //待插入BST的元素
typedef struct node  //自定义二叉搜索树的节点
{
    int data;        //键值
    node *lchild;    //左孩子
    node *rchild;    //右孩子
} BST;
void Init(BST *&b)   //初始化BST(空树)
{
    b=NULL;
}
BST *Insert(BST *&b,int x)   //向BST中插入元素x,返回BST结构体的指针
{
    if(b==NULL)      //当前节点为空时,创建新节点
    {
        b=(BST *)malloc(sizeof(BST));
        b->data=x;
        b->lchild=b->rchild=NULL;
    }
    else
    {
        if(xdata)//待插入节点比当前节点小,在左子树中插入
            b->lchild=Insert(b->lchild,x);
        else     //否则在右子树中插入
            b->rchild=Insert(b->rchild,x);
    }
    return b;
}
int Find(BST *b,int x)        //在BST中查找元素x
{
    if(b==NULL)   //当前节点为空,表示未找到,返回0
        return 0;
    else
    {
        if(b->data==x)    //当前节点为待查找节点,表示找到,返回1
            return 1;
        else if(xdata)//否则,在左子树中继续查找
            return Find(b->lchild,x);
        else      //在右子树中继续查找
            return Find(b->rchild,x);
    }
}
BST *Remove(BST *p,int x)   //在BST中删除元素x,返回BST结构体的指针
{
    BST *q,*r;
    //首先查找待删除节点x
    if(p==NULL)         //当前节点为空,表示找不到,直接返回空
        return NULL;
    else if(xdata)  //待删除节点比当前节点小,在左子树中删除
        p->lchild=Remove(p->lchild,x);
    else if(x>p->data)  //待插入节点比当前节点大,在右子树中删除
        p->rchild=Remove(p->rchild,x);
    //然后分别处理可能出现的三种情况
    else if(p->lchild==NULL)  //需要删除的节点没有左儿子
    {
        q=p->rchild;    //将右儿子提上去
        free(p);
        return q;
    }
    else if(p->lchild->rchild==NULL)  //需要删除的节点的左儿子没有右儿子
    {
        q=p->lchild;    //将左儿子提上去
        q->rchild=p->rchild;
        free(p);
        return q;
    }
    else    //其他情况
    {
        for(q=p->lchild;q->rchild->rchild!=NULL;q=q->rchild); //将左儿子的子孙中最大的节点提到需要删除的节点上
        r=q->rchild;
        q->rchild=r->lchild;
        r->lchild=p->lchild;
        r->rchild=p->rchild;
        free(p);
        return r;
    }
    return p;
}
void PreOrderBST(BST *b)      //先序遍历BST
{
    if(b!=NULL)
    {
        printf("%d ",b->data);
        PreOrderBST(b->lchild);
        PreOrderBST(b->rchild);
    }
}
void InOrderBST(BST *b)       //中序遍历BST
{
    if(b!=NULL)
    {
        InOrderBST(b->lchild);
        printf("%d ",b->data);
        InOrderBST(b->rchild);
    }
}
void PostOrderBST(BST *b)     //后序遍历BST
{
    if(b!=NULL)
    {
        PostOrderBST(b->lchild);
        PostOrderBST(b->rchild);
        printf("%d ",b->data);
    }
}
void PrintOrder(BST *b)       //打印BST先中后序遍历序列
{
    printf("PreOrderBST:");
    PreOrderBST(b);
    printf("\n");

    printf("InOrderBST:");
    InOrderBST(b);
    printf("\n");

    printf("PostOrderBST:");
    PostOrderBST(b);
    printf("\n");
}
int main()
{
    int i;
    BST *b;
    Init(b);         //初始化BST为空(很重要!)
    scanf("%d",&n);
    for(i=0;i


你可能感兴趣的:(算法笔记系列)