二叉搜索树的相关操作

操作包括二叉搜索树的创建,插入,搜索,寻找前驱后继,删除,左右旋转,插入元素为根结点,以及两棵二叉树的合并。

二叉树的创建很简单,只需要设置 value, left child, right child 即可。

插入的时候递归插入树中合适的位置,通过比较插入元素的值与根结点元素的值,如果小于则递归插入到左子树中,否则递归插入到右子树中。

搜索的时候与插入类似,比较要搜索的值和根结点元素值的大小,若小于则递归到左子树中去查找,否则递归到右子树中去查找。

寻找前驱的方式是在左子树的右结点中去递归寻找,一直找到右结点的右子结点为空,则该右结点即是前驱,寻找后继是在右子树的左结点中去递归寻找,一直找到左结点的左子结点为空,则该左结点即是后继。

结点的删除有些复杂,如果删除的叶结点,则直接删除,否则就要用该结点的前驱中的值来代替该结点中的值,然后递归删除前驱,若不存在前驱,则使用该结点的后继来代替该结点中的值,然后递归删除后继,如果后继也不存在,证明该结点是个叶子结点,直接删除即可。

左旋的方式是让根结点的右结点变成新的根结点,再让新的根结点的左结点指向原来的根结点,再让原来根结点的右结点指向新的根结点原来的左结点,这样操作之后就好像原来的根结点向左旋转了一样。

右旋的操作正好和左旋是对称的,将根结点的左结点变成新的根结点,再让新的根结点的右结点指向原来的根结点,再让原来根结点的左结点指向新的根结点原来的右结点,这样操作之后就好像根结点右旋了一样。

原来的插入操作是直接插入到叶子结点上的,而插入一个元素使其变为根结点就需要旋转操作来实现,如果插入元素大于根结点值,则递归插入到右子树中让其成为右子树的根结点,再将树左旋即可实现,若插入元素小于根结点值,则递归插入到左子树中让其成为左子树中的根结点,再将树右旋即可,递归到最后必然到叶子结点上,此时用插入元素的值来创建一个新的结点,之后依次回程旋转即可实现。

要合并两棵二叉树,基本的思路是遍历其中一棵树,然后递归插入到另一棵树中,优化方式是先将其中一棵树A的根结点插入到另外一棵树B中,此时两棵树的根结点相同,此后树A的左子树插入到树B中必然也是在左子树中,右子树也是同样。所以就可以递归将A的左结点插入到B的左子树中,将A的右结点递归插入到B的右子树中,注意因为这种方式依赖于左右子树和根结点的大小关系,所以只能采用前序递归方式,否则合并之后会破坏树中元素的先后顺序。

 

具体详见代码:

 

//BST.cpp

#include <malloc.h>
#include <iostream>
#include "binary_tree.h"//defined BST struct
#include "print_binary_tree.h"
//the node of a tree, included in binary_tree.h
#include <stdlib.h>
#include <time.h>
using namespace std;

//create node with value, left child and right child 
struct bst_node* create_bst_node(int value, struct bst_node* l, struct bst_node* r){
    struct bst_node* t =(struct bst_node*) malloc(sizeof *t);//should call free() when finished
    t->value = value;
    t->l = l;
    t->r = r;
    return t;
}

//bst insert
struct bst_node* bst_insert(struct bst_node* root, int value){
    if(root == NULL) 
        return create_bst_node(value,NULL,NULL);//tree is empty
    //if root is not NULL
    if(value < root->value)
        root->l = bst_insert(root->l,value);//insert into left child
    else if (value > root->value)
        root->r = bst_insert(root->r,value);//
    return root;
}

//bst search, the keyword "struct" can be omitted
struct bst_node* bst_search(struct bst_node* bst_root, int value){
    if(bst_root == NULL)
        return NULL;
    if(value < bst_root->value){
        return bst_search(bst_root->l, value);
    }else if(value > bst_root->value){
        return bst_search(bst_root->r, value);
    }
    return bst_root;//neither greater nor less, must be equal
}
//predecessor 
bst_node* predecessor(bst_node* t){
    t = t->l;
    while(t->r != NULL){
        t = t->r;
    }
    return t;
}
//successor 
bst_node* successor(bst_node* t){
    t = t->r;
    while(t->l != NULL){
        t = t->l;
    }
    return t;
}
//bst remove
bst_node* bst_remove(bst_node* t, int value){
    if(t == NULL) return NULL;
    if(value < t->value){
        t->l = bst_remove(t->l,value);//return a new left subtree which has removed the value
    }else if(value > t->value){
        t->r = bst_remove(t->r,value);//return a new right subtree which has removed the value
    }else{//have found the value
        if(t->l != NULL){//get the predecessor first, then remove predecessor in left subtree
            t->value = predecessor(t)->value;
            t->l = bst_remove(t->l,t->value);
        }else if(t->r != NULL){//get the successor first, then remove successor in right subtree
            t->value = successor(t)->value;
            t->r = bst_remove(t->r,t->value);
        }else{
            //now t is a leaf node,and remove it directly
            free(t);
            t = NULL;
        }
    }
    return t;
}

//bst rotate
//bst rotate right, return left child
bst_node* bst_rot_r(bst_node* t){
    if(t == NULL || t->l ==NULL) return t;
    else{
        bst_node* tl = t->l;
        t->l = tl->r;
        tl->r = t;
        return tl;
    }
}
//bst rotate left, return right child
bst_node* bst_rot_l(bst_node* t){
    if(t == NULL || t->r ==NULL) return t;
    else{
        bst_node* tr = t->r;
        t->r = tr->l;
        tr->l = t;
        return tr;
    }
}
//insert node to root
bst_node* bst_insert_to_root(bst_node* t, int value){
    if(t == NULL)//insert to leaf 
        return create_bst_node(value,NULL,NULL);
    if(value > t->value){
        t->r = bst_insert_to_root(t->r,value);
        return bst_rot_l(t);
    }else if(value < t->value){
        t->l = bst_insert_to_root(t->l,value);
        return bst_rot_r(t);
    }else{
        return t;
    }
}

//merge two trees
bst_node* bst_merge_mine(bst_node* a, bst_node* b)
{
    if (b==NULL) return a;
    if (a==NULL) return b;
    
    //get the value from a, and insert the value into b
    //我是直接从根结点开始插入
    //我的算法前序递归和后序递归都是可以的
    //中序递归会生成一颗倾斜的树,应为中序遍历结点的值往后依次是增大的
    //最后的一个元素是最大的,又成为了根结点,所以合成树是向右上方倾斜的
    b = bst_merge_mine(a->l,b);
    b = bst_merge_mine(a->r,b);
    b = bst_insert_to_root(b,a->value);//let root of a tobe the root of merged tree
    
    return b;
}

//merge two trees
//基本思想还是遍历a中的元素,递归插入到b中
//但是这个比我的算法稍微好的地方在于将a和b的根结点设置为一样之后
//每次插入可以不从b的根结点开始,因为此时a的左树插入之后必然在合并之树的左边,
//a的右子树插入之后也必然在合并之树的右边,所以插的时候a的左子树可以直接插到b的左子结点去,
//同理a的右结点可以插到b的右子树中去
bst_node* bst_merge(bst_node* a, bst_node* b)
{//整个递归过程是前序递归:root->left child->right child
    //从一开始想到这两个条件并不困难,
    //但是在递归的时候这两个条件却起到了很大作用
    //这两个条件配合下面的左右子树赋值语句b->l=... b->r=...发挥了很妙的作用
    if (a==NULL) return b;//
    if (b==NULL) return a;//这个条件很微妙,在递归的时候表现的很巧妙
    //注意,因为此处利用了左右子树和根的相互关系,所以只能是前序递归
    //中序递归和后序递归都会破坏树中元素的先后关系
    b = bst_insert_to_root(b,a->value);//set a to root
    b->l = bst_merge(a->l, b->l);//将a的左结点取出,插到b的左子树中去
    b->r = bst_merge(a->r, b->r);//将a的右结点取出,插到b的右子树中去
    free(a);//每次合并完后将a的子树释放
    a = NULL;
    return b;
}


int main(){
    //create_bst_node();
    //srand((unsigned)time(NULL));//使用系统时间初试化随机种子
    int value = rand()%123;
    bst_node* bst_root = create_bst_node(value, NULL, NULL);
    //for(int k=0; k<39; k++){
    for(int k=0; k<9; k++){
        value = rand()%123;
        bst_insert(bst_root, value);
    }

    print_binary_tree(bst_root);

    value = rand()%123;
    bst_node* bst_root2 = create_bst_node(value, NULL, NULL);
    //for(int k=0; k<39; k++){
    for(int k=0; k<9; k++){
        value = rand()%123;
        bst_insert(bst_root2, value);
    }

    print_binary_tree(bst_root2);
    bst_node* m = bst_merge(bst_root,bst_root2);
    print_binary_tree(m);
    return 0;
}

 

转载于:https://www.cnblogs.com/lengyue365/p/5090225.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值