数据结构---二叉排序树

一、二叉排序树的定义

二叉排序树,又称“二叉查找树”。(BST,Binary Search Tree)二叉排序树可用于元素的有序组织、搜索。

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树。

①若它的左子树非空,则子树上所有结点的值均于根节点的值;

②若它的右子树非空,则子树上所有结点的值均于根结点的值;

③它的左右子树也分别是二叉排序树。

左子树结点值 < 根结点值 < 右子树结点值

二叉排序树是递归定义的。由定义可以得出二叉排序树的一个重要性质:中序遍历一棵二叉树时可以得到一个结点值递增的有序序列

二、查找操作

实现思想及时间复杂度:

思想:

若树非空,目标值与根结点的值进行比较:

                  若相等,则查找成功;

                  若小于根结点,则在左子树上查找,否则在右子树上查找。

                  查找成功,返回结点指针;查找失败返回NULL。

时间复杂度:非递归实现:最坏时间复杂度O(1)

                      递归实现:最坏时间复杂度O(h):h为树高

二叉排序树查找代码实现:

非递归实现的代码:

//二叉排序树查找
//二叉排序树结点
typedef struct BSTNode{
    int key;
    struct BSTNode *lchild, *rchild;
}BSTNode, *BSTree;

//非递归实现:在二叉排序树中查找值为key的结点
BSTNode *BST_Search(BSTree T, int key){
    while(T != NULL && T->key != key){
        if(T->key < key){
            T = T->rchild;
        }else{
            T = T->lchild;
        }
    }
    return T;
}

递归实现的代码:

//递归实现:在二叉排序树中查找值为key的结点
BSTNode *BST_Search(BSTree T, int key){
    if(T == NULL){
        return NULL;//空树,查找失败
    }
    
    if(T->key == key){
        return T;//查找成功
    }else if(T->key > key){
        return BST_Search(T->lchild, key);
    }else{
        return BST_Search(T->rchild, key);
    }    
}

三、插入操作

实现思路及时间复杂度:

思路:

若原二叉排序树为空,则直接插入结点;

否则,若关键字k小于根结点,则插入其左子树;

若关键字k大于根结点,则插入右子树。

二叉树中不允许两个结点的值相等,所以当所插结点的值已存在,那么就插入失败。

时间复杂度:新插入的结点一定是叶子结点,因此最坏时间复杂度是O(h).

二叉排序树插入代码实现:

非递归实现:

//二叉排序树插入操作
//非递归实现:利用循环
int BST_Insert(BSTree &T, int k){
    if(T == NULL){//原树为空,则新插结点为根结点
        T = (BSTree)malloc(sizeof(BSTNode));
        T->key = k;
        T->lchild = T->rchild = NULL;
        return 1;
    }
    
BSTNode *parent = NULL;//当前cur的父结点
    BSTNode *cur = T;
    while(cur){//找到目前cur应该在的位置
        if(cur->key < k){
			parent = cur;
            cur = cur->rchild;
        }else if(cur->key > k){
			parent = cur;
            cur = cur->lchild;
        }else{
            return false;
        }
    }
    
    //到这里cur为空,就是k要插入的位置
    cur = (BSTree)malloc(sizeof(BSTNode));
    cur->key = k;
    cur->lchile = cur->rchild = NULL;
    //链接
    if(k < parent->key){
        parent->lchild = cur;
    }
    if(k > parent->key){
        parent->rchild = cur;
    }
    return 1;
}

递归实现:

//二叉排序树插入操作:递归实现
//二叉排序树结点
typedef struct BSTNode{
    int key;
    struct BSTNode *lchild, *rchild;
}BSTNode, *BSTree;

//在二叉排序树插入关键字为k的新结点(递归实现)
int BST_Insert(BSTree &T, int k){
    if(T == NULL){//原树为空,新插结点为根结点
        T = (BSTree)malloc(sizeof(BSTNode));
        T->key = k;
        T->lchild = T->rchild = NULL;
        return 1;
    }else if(T->key == k){//树中存在相同关键字的结点,插入失败
        return 0;
    }else if(k < T->key){
		return BST_Insert(T->lchild, k);//插左子树
    }else{//插右子树
        return BST_Insert(T->rchild, k);
    }
}

四、删除操作

实现思路及时间复杂度:

先搜索找到目标结点:

①若被删除的结点z是叶子结点,则直接删除,不会破坏二叉排序树的性质。

②若被删除结点z只有一棵左子树或右子树,则让z的子树成为z父结点的子树,代替z的位置。

③若结点z有左右两棵子树,则令z的直接后继(或直接前驱)代替z,然后从二叉排序树中删除这个直接后继(或直接前驱),这样就转换成了第①或第②种情况。

对③的解释:用直接后继来替代,即:从当前要删除的结点z的右子树中找到值最小的结点(右子树按照中序遍历第一个被访问的结点),代替z的位置。

用直接前驱来代替,即:从当前要删除的结点z的左子树中找到值最大的结点(左子树按中序遍历最后一个被访问的结点),代替z的位置。

五、查找效率分析

平均查找长度的数量级就是查找操作的时间复杂度。

-查找成功:

查找长度:在查找运算中,需要对比关键字的次数称为查找长度,反映了查找操作时间复杂度。

若树高h,找到最下层的一个结点需要对比h次。

最好情况:n个结点的二叉树最小高度为⌊log2n⌋+1。平均查找长度 = O(log2n)

最坏情况:每个结点只有一个分支,树高h = 结点数n。平均查找长度 = O(n)

-查找失败:

查找失败的结点只能出现在,最下层叶子结点的下方。因此查找失败的平均查找长度ASL与树高h密切相关。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值