二叉搜索树BST

二叉搜索树,也称有序二叉树,排序二叉树,是指一棵空树或者具有下列性质的二叉树:

1. 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

2. 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

3. 任意节点的左、右子树也分别为二叉查找树。

4. 没有键值相等的节点。

通过中序遍历可以得到一个有序数列。一个无序序列可以通过构造一棵二叉排序树变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。每次插入的新的结点都是二叉排序树上新的叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可。搜索,插入,删除的复杂度等于树高,O(log(n)).

(1)BST的建立

首先需要建立一个节点Node的结构体,这个结构体表示每个Node节点包括数值,左孩子,右孩子。当然一般还加上一个构造函数用于后面的初始化。

struct Node
{
    int val;
    Node* left;
    Node* right;
    Node( const int& value)  :left(NULL)  ,right(NULL)  ,val(value)  {}
};

另外我们就要像新建一个链表一样来完成一个二叉搜索树的创建。这里采用的是每输入一个值,以-1作为结束,就调用插入函数Insert(这个函数自己定义实现,后面会说),Insert函数会将这个节点连接到它该在的位置。Insert函数需要的参数是root根节点和插入的值value的值。注意这里root根节点要用引用传递,否则我每次调用完函数,root节点不变。

Node* creatBST()
{
    Node *root;
    root=NULL;
    int a;
    cin>>a;
    while(a!=-1)
    {
        Insert(root,a);
         cin>>a;
    }
    return root;
}

(2)BST的输出

我们利用BST的性质,因为BST的中序遍历就是一个有序的数列,所以我们输出用中序遍历来检测我们的程序结果。

void _InOrder(const Node* root)
{
    if (root == NULL)
      return;
  _InOrder(root->left);
  cout << root->val << " ";
  _InOrder(root->right);
}

这里采用的是递归形式的中序遍历。非递归形式,需要大家去学习,我前面有总结过。

(3)BST的插入

插入的操作很简单,有递归和非递归(迭代)两种实现方法。我们首先总结BST插入的迭代实现方法。

首先我们要明白,BST的插入永远是插入到叶子节点的后面,所以不会出现插入到中间的情况,我们只需要去比较每个节点的值和当前需要插入的值的大小,就能找到正确的插入位置。这里用两个Node型的指针,cur指向当前位置,parent指向当前位置的父节点。cur负责找到要插入的位置,parent负责插入的实现。

bool Insert(Node* &root,const int& value)
{
    if (root == NULL)
    {
        root = new Node(value);
    }
    Node* cur=root;
    Node* parent = NULL;
    //首先找到要插入的位置
    while (cur)
    {
        if (cur->val > value)
        {
            parent = cur;
            cur = cur->left;
        }
        else if(cur->val<value)
        {
            parent = cur;
            cur = cur->right;
        }
        else
        {
            return false;
        }
    }
    //在找到插入位置以后,判断插入父亲节点的左边还是右边
    if (parent->val > value)
    {
        parent->left = new Node(value);
    }
    else
    {
        parent->right = new Node(value);
    }
    return true;
}

递归形式也很简单

bool Insert(Node*& root, const int& value)
{
    if (root == NULL)
    {
        root = new Node(value);
        return true;
    }
    if (root->val > value)
    {
        return Insert(root->left, value);
    }
    else if(root->val < value)
    {
        return Insert(root->right,value);
    }
    else
    {
        return false;
    }
}  

(3)BST的删除操作

BST的删除是最复杂的,之所以复杂,是因为要分几种情况。所以我们只要弄清楚删除一个节点的逻辑,程序的实现自然不难。

二叉搜索树的删除:

主要分三大种情况,(1)如果要删除的节点只有左子树,那么就将该节点的父节点指向该节点的左子树,删除该节点就好了

(2)如果要删除的节点只有右子树,那么就将该节点的父节点指向该节点的右子树,删除该节点就好了

(3)如果要删除的节点左右子树都有,那么就要找比该节点的左节点要大一个数的节点,这个时候自然不能直接将右子树直接提上去,所以我们要找该节点右子树的最左孩子,也就是右子树中序遍历的第一个数。

bool Remove(Node* &root,const int& value)
{
    //没有节点
    if (root == NULL)
    {
        return false;
    }
    //只有一个节点
    if (root->left == NULL&&root->right == NULL)
    {
        if (root->val == value)
        {
            delete root;
            root = NULL;
            return true;
        }
        return false;
    }  

    Node* parent = NULL;
    Node* cur = root;
    //遍历查找要删除节点的位置
    while (cur)
    {
        Node* del = NULL;
        if (cur->val > value)
        {
            parent = cur;
            cur = cur->left;
        }
        else if (cur->val < value)
        {
            parent = cur;
            cur = cur->right;
        }
        else
        {
            //要删除节点的左子树为空,分3种情况
            if (cur->left == NULL)
            {
                //注意判断父节点是否为空,若为空,则要删除的节点为根节点
               /* if (parent == NULL)
                {
                    root = cur->right;
                    delete cur;
                    cur = NULL;
                    return true;
                }  */
                if (parent->val > cur->val)
                {
                    del = cur;
                    parent->left = cur->right;
                    delete del;
                    return true;
                }
                else if (parent->val < value)
                {
                    del = cur;
                    parent->right = cur->right;
                    delete del;
                    return true;
                }
            }
            //要删除节点的右子树为空,同样分3种情况
            else if (cur->right == NULL)
            {
                //注意判断父节点是否为空,若为空,则要删除的节点为根节点,如:只有根节点5和其左节点3
             /*   if (parent == NULL)
                {
                    root = cur->left;
                    delete cur;
                    cur = NULL;
                    return true;
                }  */
                if (parent->val > cur->val)
                {
                    del = cur;
                    parent->left = cur->left;
                    delete del;
                    return true;
                }
                else if (parent->val < cur->val)
                {
                    del = cur;
                    parent->right = cur->left;
                    delete del;
                    return true;
                }
            }
            //左右子树都不为空
            else
            {
                Node* del = cur;
                Node* parent = NULL;
                Node* RightFirst = cur->right;
                //右边第一个节点的左子树为空
                if (RightFirst->left == NULL)
                {
                    swap(RightFirst->val, cur->val);
                    del = RightFirst;
                    cur->right = RightFirst->right;
                    delete del;
                    return true;
                }
                //右边第一个节点的左子树不为空
                while (RightFirst->left)
                {
                    parent = RightFirst;
                    RightFirst = RightFirst->left;
                }
                   swap(RightFirst->val, cur->val);
                   del = RightFirst;
                   parent->left = RightFirst->right;
                   delete del;
                   return true;
            }
        }
    }
    return false;
}  

递归形式也可以写

bool Remove(Node*& root, const int& value)
{
    //没有节点
    if (root == NULL)
    {
        return false;
    }
    //只有一个节点
    if (root->left == NULL&&root->right == NULL)
    {
        if (root->val == value)
        {
            delete root;
            root = NULL;
            return true;
        }
        else
        {
            return false;
        }  

    }  

    //删除二叉搜索树节点的递归写法
    if (root->val > value)
    {
        Remove(root->left, value);
    }
    else if (root->val <value)
    {
        Remove(root->right, value);
    }
    else
    {
        Node* del = NULL;  

        if (root->left == NULL)
        {
            del = root;
            root = root->right;
            delete del;
            del = NULL;
            return true;
        }
        else if (root->right == NULL)
        {
            del = root;
            root = root->left;
            delete del;
            del = NULL;
            return true;
        }
        else
        {
            Node* RightFirst = root->right;  

            while (RightFirst->left)
            {
                RightFirst = RightFirst->left;
            }  

            swap(root->val, RightFirst->_val);  

            Remove(root->right, value);
            return true;
        }
    }
}  

原文地址:https://www.cnblogs.com/mini-coconut/p/9193622.html

时间: 2024-10-09 16:15:42

二叉搜索树BST的相关文章

【数据结构】第9章 查找! (二叉搜索树BST AVL树 B-(+)树 字典树 HASH表)

难产的笔记...本来打算用1天 结果前前后后拖了5天 §9.1 静态查找表 9.1.1 顺序表的查找 各种扫 自己脑补吧 复杂度O(n) 9.1.2 有序表的查找 若表是单调的,则可以利用二分查找.复杂度O(logn) 9.1.3 静态树表的查找 见 http://blog.csdn.net/area_52/article/details/43795837 9.1.4 索引顺序表的查找 建立索引表查找 §9.2 动态查找表 动态查找表的特点是,表结构本身是在查找过程中动态生成的,即对于给定值ke

[数据结构]二叉搜索树(BST) VS 平衡二叉排序树(AVL) VS B树(平衡多路搜索树) VS B+树 VS 红黑树(平衡二叉B树)

1 二叉排序树/二叉查找树/Binary Sort Tree 1种对排序和查找都很有用的特殊二叉树 叉排序树的弊端的解决方案:平衡二叉树 二叉排序树必须满足的3条性质(或是具有如下特征的二叉树) 若它的左子树不为空,则:左子树上所有结点的值< 它根结点的值 若它的右子树不为空,则:右子树上所有结点的值 > 它根结点的值 它的左子树.右子树也分别为二叉排序树(递归性) (按照如上定义,即: 1 无键值相等的结点 2 中序遍历一颗二叉树时,可得一个结点值递增的有序序列) 2 平衡二叉排序树/Bal

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

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

算法导论—二叉搜索树(BST)

华电北风吹 天津大学认知计算与应用重点实验室 日期:2015/9/9 与散列表一样,搜索树数据结构也支持动态集合操作,包含插入,查询,删除,最小值,最大值,前驱,后继等. 一.二叉搜索树: 二叉搜索树节点:关键字key,卫星数据,左孩子指针,右孩子指针,父节点指针,其他特殊类型(红黑树的节点颜色,AVL树的树高等). 二叉搜索树性质:x是二叉搜索树中的任意一个节点.若y是x左子树中任意一个节点有x.key>=y.key.若y是x右子树中任意一个节点有x.key<=y.key. 二.二叉搜索树的

二叉搜索树(BST)

(第一段日常扯蛋,大家不要看)这几天就要回家了,osgearth暂时也不想弄了,毕竟不是几天就能弄出来的,所以打算过完年回来再弄.这几天闲着也是闲着,就掏出了之前买的算法导论看了看,把二叉搜索树实现了下. #include <iostream> #include <memory> #include <vector> using namespace std; //节点结构 struct Node { int key; int num; shared_ptr<Node

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

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

108. 将有序数组转换为二叉搜索树-BST与AVL (leetcode)

AVL,在本题中: 1.由于构造的树的AVL,其子树高度差不超过1. 所以在选值时,要选nums中间的值作为node 2.由于每一颗子树都是AVL,所以需要使用递归 每次都选择区间中值构造Node 代码借鉴官方答案: class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None class Solution: def sortedArrayToBST(self, nums: List[

把二叉搜索树转化成更大的树 &#183; Convert BST to Greater Tree

[抄题]: 给定二叉搜索树(BST),将其转换为更大的树,使原始BST上每个节点的值都更改为在原始树中大于等于该节点值的节点值之和(包括该节点). Given a binary search Tree `{5,2,13}`: 5 / 2 13 Return the root of new tree 18 / 20 13 [暴力解法]: 时间分析: 空间分析: [思维问题]: [一句话思路]: 反向求和并把和赋给root.val [输入量]:空: 正常情况:特大:特小:程序里处理到的特殊情况:异常

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

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