二叉搜索树及其相关操作

二叉搜索树简要提点

  • 二叉树(binary tree)是一种树型数据结构,其中它的每个节点最多有两个孩子(可以没有,也可以只有一个)。
  • 二叉搜索树(binary search tree)是一种特殊的二叉树,对每个节点,其左孩子/左子树的关键字值该节点的关键字值;其右孩子/右子树的关键字值都大于该节点的关键字值。
  • 二叉搜索树的平均深度为 O(logN) O ( log ⁡ N ) 。其中, N N <script type="math/tex" id="MathJax-Element-2">N</script>为节点总数。
  • 二叉搜索树的主要操作有:创建(初始化)二叉树,查找关键字Find,返回最大最小关键字FindMax, FindMin,向树中插入元素Insert,删除节点Delete,遍历二叉树。
  • 涉及到二叉树的操作有两种方法实现:递归实现和非递归实现。

二叉搜索树及其相关操作


创建二叉搜索树

一、二叉(搜索)基本数据结构

  • 树是由一个个节点构成,节点的构成成一般为:该节点包含的关键字值(data),left指针指向其左孩子,right指针指向其右孩子。
  • 节点结构的一般声明如下:
typedef struct _TreeNode {  // 定义二叉查找树的结构
    ElemType data;          // 数据
    struct _TreeNode* left;         // 指向左孩子指针
    struct _TreeNode* right;        // 指向其右孩子指针 
}TreeNode, *SearchBTree;    // TreeNode表示节点别称,*SearchBTree表示一个指向树(子树)根节点的指针

二、初始化树

  • 一般初始化树为一个(TreeNode类型的)空指针
  • 初始化树可以和树的销毁工作合并成MakeEmpty()函数,递归地实现如下。
SearchBTree EmptyTree(SearchBTree T)    // 初始化、构造一颗空树/销毁一颗树
{
    if (!T)
    {
        EmptyTree(T->left);     // 递归地释放空间
        EmptyTree(T->right);
        delete T;
    }
    return nullptr;
}

向二叉搜索树中插入元素

  • 根据树的结构特点,比较要插入元素X值与节点关键字的大小,递归地插入(一般递归实现比较简单)。
  • 当X值小于某个节点的值,则递归地往其左子树中插入X;当X值大于某个节点的值,则递归地往其右子树中插入X。
  • 递归的终止条件是节点为空,申请一个新节点关键字为X插入到树中。
void Insert(SearchBTree &T, ElemType x)
{
    if (!T)
    {
        TreeNode* pT = new TreeNode;        // 申请节点空间
        pT->data = x;                       // 为节点赋值
        pT->left = pT->right = nullptr;
        T = pT;                             // 将pT赋给T
    }
    else
    {
        if (x < T->data)                // 如果x小于某个结点的数据
            Insert(T->left, x);         // 递归地在其左子树上寻找空结点插入
        else if (x > T->data)           // 如果x大于某个结点的数据
            Insert(T->right, x);        // 递归地在其左子树上寻找空结点插入
    }
}

在二叉搜索树中查找

  • 在树中查找某个关键字值,并返回其所在节点。
  • 递归地进行:从根节点开始,当前节点大于其查找的值,则递归地再其左子树中查找。否则,在其右子树中递归地查找。
  • 递归终止的条件是:查找到该关键字所在节点并返回。返回空结点,表示树中没有要查找的关键字值。
TreeNode* Find(SearchBTree T, ElemType x)   // 查找树中是否有值x
{
    if (T == nullptr)           // 没有找到,返回空指针
        return nullptr;
    if (x < T->data)            // 递归查找
        return Find(T->left, x);
    else if (x > T->data)
        return Find(T->right, x);
    else
        return T;               // 查找到了,则返回T指针
}
  • 查找树中的最小值
  • 1.递归实现:递归地查找其左子树。
TreeNode* FindMin(SearchBTree T)    // 查找最小值,递归实现
{
    if (T->left == nullptr)
        return T;
    else
        return FindMin(T->left);
}
  • 2.非递归实现:从根节点开始,循环遍历每个结点的左孩子,发现左孩子为空,则停止并返回该结点。
TreeNode* FindMin2(SearchBTree T)   // 查找最小值,非递归实现
{
    while (T->left != nullptr)
        T = T->left;
    return T;
}
  • 查找树中的最大值
  • 递归实现:递归地查找其右子树。
TreeNode* FindMax(SearchBTree T)    // 查找最大值
{
    if (T->right == nullptr)
        return T;
    else
        return FindMax(T->right);
}

删除二叉搜索树中的某个节点

  • 分两种情况:
  • 1.删除的节点是树叶节点(没孩子):则直接删除。
  • 2.删除的节点是(子树的)根节点:也分两种情况:① 该节点有一个孩子,则直接替换为其孩子节点,然后删除释放其自身。
  • ② 该节点有两个孩子,先把该节点的关键字值替换为其右子树的最左边孩子的关键字值(最小值)。然后再删除其右子树自身的最小值。
void Delete(SearchBTree &T, ElemType x)     // 删除指定元素
{
    TreeNode *tmpNode = new TreeNode;   // 创建一个临时结点
    if (T == nullptr)           // 没有x存在
        cout << "404 Not Found\n";
    else if (x < T->data)       // x小于某个结点值
        Delete(T->left, x);     // 递归地从其左子树删除x
    else if (x > T->data)       // x大于某个结点的值
        Delete(T->right, x);    // 递归地从其右子树删除x
    else                        // 找到了x
    {
        if (T->left&&T->right)  // x所在结点有两个孩子的情况
        {
            tmpNode = FindMin(T->right);        // 将临时结点赋值为其右子树中具有最小值的结点(即最左端的结点)
            T->data = tmpNode->data;            // 移动数据至要删除的目标结点
            Delete(T->right, tmpNode->data);    // 删除其右子树中值为x的结点
        }
        else
        {   // x所在结点只有一个孩子和没有孩子的情况
            tmpNode = T;        // 要删除的结点T赋给临时结点tmpNode
            if (T->left == nullptr)     // 若当前结点的左孩子为空
                T = T->right;           // 则,将当前结点赋值为其右孩子
            else if (T->right == nullptr)   // 若当前结点的右孩子为空
                T = T->left;                // 则,将当前结点赋值为其左孩子
            else
                delete tmpNode;             // 否则当前结点为叶子结点(没有孩子),则直接释放
        }
    }
}

递归遍历二叉搜索树

  • 二叉搜索树主要有三种遍历方式:先根(序)遍历,中根(序)遍历,后根(序)遍历
  • 1.先根遍历:先访问根节点,再递归地遍历其左子树,最后再递归地遍历其右子树
void PreorderPrint(SearchBTree T)       // 先根(序)遍历二叉树并打印出结点值
{
    if (T != nullptr)
    {
        cout << T->data << " ";
        PreorderPrint(T->left);
        PreorderPrint(T->right);
    }
}
  • 1.中根遍历:先递归地遍历其左子树,然后再访问根节点,最后再递归地遍历其右子树
void InorderPrint(SearchBTree T)        // 中根(序)遍历二叉树并打印出结点值
{
    if (T != nullptr)
    {
        InorderPrint(T->left);
        cout << T->data << " ";
        InorderPrint(T->right);
    }
}
  • 3.后根遍历:先递归地遍历其左子树,再递归地遍历其右子树,最后再访问根节点
void PostorderPrint(SearchBTree T)      // 中根(序)遍历二叉树并打印出结点值
{
    if (T != nullptr)
    {
        PostorderPrint(T->left);
        PostorderPrint(T->right);
        cout << T->data << " ";
    }
}

相关操作及运行结果

C/C++主程序

int main()
{
    const ElemType rawdata[] = { 19, 7, 9, 15, 23, 39, 4, 2, 75, 100, 43, 58 };
    SearchBTree myTree = new TreeNode;
    myTree = EmptyTree(myTree);     // 初始化树
    for (int i = 0;i < sizeof(rawdata) / sizeof(ElemType);i++)
    {
        Insert(myTree, rawdata[i]);     // 向树中插入给定数据
    }
    cout << "The preorder print of the tree is: \n";
    PreorderPrint(myTree);
    cout << endl;
    cout << "The inorder print of the tree is: \n";
    InorderPrint(myTree);
    cout << endl;
    cout << "The postorder print of the tree is: \n";
    PostorderPrint(myTree);
    cout << endl;
    cout << "Input a value: ";
    ElemType x;
    cin >> x;
    if (Find(myTree, x))
        cout << x << "is in the tree.\n";
    else
        cout << x << "is not in the tree.\n";

    TreeNode* TmpNode = new TreeNode;
    TmpNode = FindMin(myTree);
    cout << "The minimum value in the tree is: " << TmpNode->data << endl;
    TmpNode = FindMax(myTree);
    cout << "The maximum value in the tree is: " << TmpNode->data << endl;
    cout << "Input a value to delete: ";
    cin >> x;
    Delete(myTree, x);
    cout << "Now, the inorder print of the tree is: \n";
    InorderPrint(myTree);
    cout << "\nDestroy the tree..." << endl;
    EmptyTree(myTree);
    system("pause");
    return 0;
}

操作运行结果

The preorder print of the tree is:
19 7 4 2 9 15 23 39 75 43 58 100
The inorder print of the tree is:
2 4 7 9 15 19 23 39 43 58 75 100
The postorder print of the tree is:
2 4 15 9 7 58 43 100 75 39 23 19
Input a value to search: 13
13 is not in the tree.
The minimum value in the tree is: 2
The maximum value in the tree is: 100
Input a value to delete: 58
Now, the inorder print of the tree is:
2 4 7 9 15 19 23 39 43 75 100
Destroy the tree...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值