data structure and algorithms程序员

二叉搜索树(Binary Search Tree)

2018-04-28  本文已影响0人  spraysss

什么是二叉查找树

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

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

BST

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

BST

BST查询相关的操作

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

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

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;
}
上一篇下一篇

猜你喜欢

热点阅读