美文网首页data structure and algorithms程序员
二叉搜索树(Binary Search Tree)

二叉搜索树(Binary Search Tree)

作者: spraysss | 来源:发表于2018-04-28 21:08 被阅读0次

    什么是二叉查找树

    二叉搜索树,以下简称BST。他有如下特性:

    • 它是一个二叉树。
    • 如果x是BST的一个节点,L为x的左子树中的任意一个节点,R为x的右子树中的任意一个节点,满足
      L.key \leq x.key \geq R.key

    搜索树支持很多动态集操作(dynamic-set),比如SEARCH, MINIMUM, MAXIMUM, PREDECESSOR, SUCCESSOR,INSERT, 和DELETE 因此,我们可以将搜索树用作字典和优先级队列

    BST

    如果中序遍历BST将会得到一个有序的序列。这个是显然的,二叉树的性质就是左边元素小,右边元素大,按左中右的顺序遍历得到的就是有序的。

    BST

    BST查询相关的操作

    ①元素查找
    在BST中查找关键字为k的节点,查找成功返回指向该节点的指针,失败返回NULL;
    ②最大值和最小值
    最大值在最右边
    最小值在最左边
    ③前驱和后继
    节点x的前驱是指比他小的最大一个节点
    节点x的后继是指比他大的最小一个节点

    求节点的前驱和后继节点是对称的,前驱和后继节点可能不存在,比如一个BST中最大值没有后继,最小值没有前驱。下面以求后继为例,求后继节点分为两种情况:

    • case1: 有右孩子,这种情况比较简单s,直接转化为以右孩子为根节点的子树的最小值。即y节点。


      存在右孩子
    • case2:没有右孩子,需要向上查找第一个左拐的祖先


      没有右孩子

    We can implement the dynamic-set operations SEARCH, MINIMUM, MAXIMUM,
    SUCCESSOR, and PREDECESSOR so that each one runs in O(h) time on a binary
    search tree of height h

    ④插入
    插入和查找类似,需要一个尾指针记录插入的位置
    ⑤删除
    删除操作分为三种情况
    1.要删除的节点没有左右孩子。直接删除
    2.要删除的节点只有左孩子或只有右孩子。例如要删除z,只需要将z的parent q和l链接起来就行。


    只有一个孩子

    3.要删除的节点既有左孩子也有右孩子 。删除思想是使用后继替换删除的节点转化为第二种情况。根据删除节点的后继是否为删除节点的右孩子,又可以分为两种情况:
    3.1 删除节点的后继为右孩子:


    后继为右孩子

    3.2 删除节点的后继不是右孩子:


    后继不是右孩子

    c语言实现

    BST.h

    #ifndef BST_H
    #define BST_H 
    #endif
    #include<stdio.h>
    #include<stdlib.h>
    typedef  int BSTELEM_TYPE;
    //typedef enum{false,true } bool;//定义bool 
    #define EQ(a,b) ((a)==(b))
    #define LT(a,b) ((a)<(b))
    typedef struct BSTNode{
        struct BSTNode *left;
        struct BSTNode *right;
        struct BSTNode *parent;
        BSTELEM_TYPE key;
    }BSTNode,*BSTTree;
    //递归查找 
    //根据指针x所指的BST中递归的查找关键字等于k 的元素
    //若查找成功返回指向该数据元素节点的指针,失败返回null; 
    BSTTree Tree_Search(BSTTree x,BSTELEM_TYPE k);
    //迭代查找
    BSTTree Iterative_Tree_Search(BSTTree x,BSTELEM_TYPE k); 
    //查找x指针指向的BST的最小值
    BSTTree Tree_Minimum(BSTTree x);
    //查找x指针指向的BST的最大值
    BSTTree Tree_Maximum(BSTTree x); 
    //查找x指针指向的BST的后继 
    BSTTree Tree_Successor(BSTTree x); 
    BSTTree Tree_Predecessor(BSTTree x);
    int Tree_Insert(BSTTree *t,BSTELEM_TYPE k);
    //递归实现中序遍历 
    void inOrderTraverse(BSTTree t);
    void Transplant(BSTTree *x,BSTTree *y);
    void Tree_Delete(BSTTree *t, BSTELEM_TYPE k) ;
    

    BST.c

    #ifndef BST_C
    #define BST_C
    #endif
    
    #include "BST.h"
    
    BSTTree Tree_Search(BSTTree x,BSTELEM_TYPE k){
        //x为空或者x指向的元素等于k,查找结束 
        if((x==NULL)||EQ(k,x->key)){
            return x;
        //k 小于x指向的元素,在左子树中查找    
        }else if(LT(k,x->key)) {
            return Tree_Search(x->left,k);
        //k 大于x指向的元素,在右子树中查找 
        }else {
            return Tree_Search(x->right,k);
        }
    }
    BSTTree Iterative_Tree_Search(BSTTree x,BSTELEM_TYPE k){
        while(x&&!EQ(k,x->key)){
            if(LT(k,x->key)){
                x=x->left; 
            }else{
                x=x->right;
            }
        }
        return x;
    }
    BSTTree Tree_Minimum(BSTTree x){
        if(!x){
            return NULL; 
        }
        while(!x->left){
            x=x->left;
        }
        return x;
    } 
    BSTTree Tree_Maximum(BSTTree x){
            if(!x){
            return NULL; 
        }
        while(!x->right){
            x=x->right;
        }
        return x;
    } 
    BSTTree Tree_Successor(BSTTree x){
        //case 1 有右孩子 ,直接返回右孩子的最小值 
        if(x->right!=NULL){
            return Tree_Minimum(x->right);
        }
        //case 2 没有右孩子,找到第一个左拐的祖先 
        BSTTree y=x->parent;
        while(y!=NULL&&y->right==x){//右拐的都是比他小的,继续循环 
            x=y;
            y=y->parent;
        }
        return y;
         
    }
     
    BSTTree Tree_Predecessor(BSTTree x){
        //case1 有左孩子,直接返回左孩子的最大值 
        if(x->left!=NULL){
            return Tree_Maximum(x->left);       
        } 
        BSTTree y=x->parent;
        while(y!=NULL&&y->left==x){//左拐的都是比他大的,继续向上
            x=y;
            y=y->parent; 
        } 
        return y;   
    }
    int Tree_Insert(BSTTree *t,BSTELEM_TYPE k){
        //重复元素不插入 
        if(Iterative_Tree_Search(*t,k)){
            return 0;
        }
        //z为待插入元素,为期动态分配空间同时初始化 
        BSTTree z=(BSTTree)malloc(sizeof(BSTNode));
        z->key=k;
        z->left=z->right=z->parent=NULL;
        //树为空直接插入 
        if(*t==NULL){
            *t=z;
            return 1;
        }
        
        BSTTree y;//记录待插入节点z的父亲指针,尾指针 
        BSTTree x=*t;
        while(x!=NULL){
            y=x;
            if(LT(k,x->key)){
                x=x->left;
            }else{
                x=x->right;
            }
        } 
        //y即为z的父指针 
        z->parent=y;
        if(LT(k,y->key)){
            y->left=z;
        }else{
            y->right=z;
        }
        return 1;
    }
    void inOrderTraverse(BSTTree t){
        if(t){
            inOrderTraverse(t->left);
            printf("%d",t->key);
            inOrderTraverse(t->right);
        }
        
    }
    
    //将x的父节点和y连起来 
    void Transplant(BSTTree *x,BSTTree *y){
        if((*x)->parent==NULL){
            return;
        }else if((*x)->parent->left==*x){
            (*x)->parent->left=*y;
        }else{
            (*x)->parent->right=*y;
        }
        if(*y!=NULL){
            (*y)->parent=(*x)->parent;
        }
        
    }
    void Tree_Delete(BSTTree *t, BSTELEM_TYPE k) {
        BSTTree z=Iterative_Tree_Search(*t,k);
        //要删除的节点不存在,直接返回 
        if(z==NULL){
            return ;
        }
        //左孩子不存在 
        if(z->left==NULL){
            Transplant(&z,&z->right);
        //右孩子不存在 
        }else if(z->right==NULL){
                Transplant(&z,&z->left);
        }else {
            BSTTree y=  Tree_Successor(z);
            if(y->parent!=z){//后继不是右孩子 
                Transplant(&y,&y->right);
                y->right=z->right;
                y->right->parent=y;
                }   
            Transplant(&z,&y) ;
            y->left=z->left;
            y->left->parent=y;
            }
            z->left=z->right=z->parent=NULL;
            free(z); 
        
            
        
    }
    void createBST(BSTTree *t,int  a[],int n){
        int i=0;
        for(i;i<n;i++){
            Tree_Insert(t,a[i]);
        }
    }
    int main(){
        BSTTree t=NULL;
        int a[]={10,5,15,18,17,16};
        //创建BST 
        createBST(&t,a,sizeof(a)/sizeof(int));  
        //删除key为15的节点 
        Tree_Delete(&t,15);
        中序遍历 
        inOrderTraverse(t);
        return 0;
    }
    

    相关文章

      网友评论

        本文标题:二叉搜索树(Binary Search Tree)

        本文链接:https://www.haomeiwen.com/subject/bpfglftx.html