二叉搜索树的相关操作

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

二叉树的创建很简单,只需要设置 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;
}
时间: 2024-10-15 11:13:05

二叉搜索树的相关操作的相关文章

C++实现二叉搜索树的常用操作

实现操作 (1)二叉搜索树的建立 (2)二叉搜索树的插入 (3)二叉搜索树的三种递归遍历(前序.中序和后续) (4)二叉搜索树的三种非递归遍历(前序.中序和后续) (5)二叉搜索树的逐层打印 (6)搜索某一个字符(递归算法) (7)搜索一个字符(非递归算法) (8)查找最大元素 (9)查找最小元素 有时间再实现: (10)二叉搜索树的前驱和后继查找 (11)二叉搜索树的删除 源码分析: #include <iostream> #include <stack> #include &l

二叉搜索树的删除操作详解(BST)

一.思想:分类讨论 二.二叉搜索树的删除操作具体讨论分如下四种情况:(记我们要删除的节点为D) 1.如果D节点既没有左孩子,也没有右孩子,那么直接删除就好了: 2.如果D节点只有左孩子,没有右孩子,那么只需要把该D节点左孩子链接到D节点的父亲节点,然后删除D节点就好了: 3.如果D节点只有右孩子,没有左孩子,那么只需要把该D节点右孩子链接到D节点的父亲节点,然后删除D节点就好了: 4.如果D节点既有左孩子,又有右孩子,那么需要找到D节点的右子树的最小值节点,找到之后直接替换掉D节点,然后删除找到

二叉搜索树的一些操作的C++实现

头文件: #include<iostream> using namespace std; typedef struct BiTNode { int data; int key; struct BiTNode *parent, *lchild, *rchild; }BiTNode, *BiTree; BiTree Tree_Search(BiTree x, int k); void Tree_Walk(BiTree x); BiTree Tree_Minimun(BiTree x); BiTre

二叉搜索树以及对二叉搜索树平衡调整

代码的思想和图片参考:好大学慕课浙江大学陈越.何钦铭的<数据结构> 我们首先介绍一下什么是二叉搜索树和二叉平衡树: 二叉搜索树:一棵二叉树,可以为空:如果不为空,满足以下性质1. 非空左子树的所有键值小于其根结点的键值.2. 非空右子树的所有键值大于其根结点的键值.3. 左.右子树都是二叉搜索树. 二叉搜索树操作的特别函数:Position Find( ElementType X, BinTree BST ):从二叉搜索树BST中查找元素X,返回其所在结点的地址,查找的次数取决于树的高度  

数据结构-二叉搜索树(BST binary search tree)

本文由@呆代待殆原创,转载请注明出处:http://www.cnblogs.com/coffeeSS/ 二叉搜索树简介 顾名思义,二叉搜索树是以一棵二叉树来组织的,这样的一棵树可以用一个链表数据结构来表示,每个节点除了key和卫星数据(除了二叉树节点的基本数据以外人为添加的数据,这些数据和树的基本结构无关),还有left.right.parent,分别指向节点的左孩子.右孩子和父节点,如果对应的节点不存在则指向NIL节点(因为最简单的二叉搜索树中的NIL节点里并没有有用的信息,所以在实现的时候简

二叉搜索树(BST)---python实现

github:代码实现 本文算法均使用python3实现 1. 二叉搜索树定义 ??二叉搜索树(Binary Search Tree),又名二叉排序树(Binary Sort Tree). ??二叉搜索树是具有有以下性质的二叉树: ??(1)若左子树不为空,则左子树上所有节点的值均小于或等于它的根节点的值. ??(2)若右子树不为空,则右子树上所有节点的值均大于或等于它的根节点的值. ??(3)左.右子树也分别为二叉搜索树. 2. 二叉搜索树的相关操作 2.1 插入操作 ??从根节点开始,若插入

数据结构 - 从二叉搜索树说到AVL树(一)之二叉搜索树的操作与详解(Java)

二叉搜索树(Binary Search Tree),简称BST,顾名思义,一颗可以用于搜索的二叉树.BST在数据结构中占有很重要的地位,一些高级树结构都是其的变种,例如AVL树.红黑树等,因此理解BST对于后续树结构的学习有很好的作用.同时利用BST可以进行排序,称为二叉排序,也是很重要的一种思想. 二叉树的性质:任意一个节点的所有左子树元素都比该元素值要小,而所有右子树元素都比该元素值要大. 符合该性质的二叉树就是一颗二叉搜索树,当然前提下是树中不允许有重复元素. 所有的二叉搜索树的中序遍历序

二叉搜索树的局限性

-------------------siwuxie095 二叉搜索树的局限性 二叉搜索树在时间性能上是具有局限性的 同样的数据,可以对应不同的二叉搜索树,如下: 二叉搜索树可能退化成链表,相应的,二叉搜索树的查找操作是和这棵树 的高度相关的,而此时这颗树的高度就是这颗树的节点数 n,同时二叉搜 索树相应的算法全部退化成 O(n) 级别 显然,说二叉搜索树的查找.插入.删除 这三个操作都是 O(lgn) 级别的, 只是一个大概的估算,具体要和二叉搜索树的形状相关 二叉搜索树并不能像堆那样,保证所

算法导论第十二章 二叉搜索树

一.二叉搜索树概览 二叉搜索树(又名二叉查找树.二叉排序树)是一种可提供良好搜寻效率的树形结构,支持动态集合操作,所谓动态集合操作,就是Search.Maximum.Minimum.Insert.Delete等操作,二叉搜索树可以保证这些操作在对数时间内完成.当然,在最坏情况下,即所有节点形成一种链式树结构,则需要O(n)时间.这就说明,针对这些动态集合操作,二叉搜索树还有改进的空间,即确保最坏情况下所有操作在对数时间内完成.这样的改进结构有AVL(Adelson-Velskii-Landis)