• 二叉排序树


    一、定义

    二叉排序树,又叫二叉查找树,它或者是一棵空树;或者是具有以下性质的二叉树:
    1. 若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
    2. 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
    3. 它的左右子树也分别为二叉排序树。

    如下图所示:

     二、二叉排序树的C++实现

    1、结点定义

    为简单起见,这里将结点的键值类型设为int.

    class BSTNode {
    public:
        int key;            //结点的值
        BSTNode* left;        //结点的左孩子
        BSTNode* right;        //结点的右孩子
        BSTNode* parent;    //结点的双亲
    
        /*构造函数*/
        BSTNode():parent(NULL) {}
        BSTNode(int key, BSTNode* left, BSTNode* right, BSTNode* parent) :key(key), left(left), right(right), parent(parent) {}
    };

     2、二叉排序树的各种操作

    class BSTree {
    private:
        BSTNode* root;        //根节点
    public:
        /*构造函数*/
        BSTree() :root(NULL) {};
    
        /*获取根节点*/
        BSTNode* getRoot() {return root;}
    
        /*将键值key插入到二叉树中*/
        void insert(int key);
    
        /*将结点插入到二叉树中*/
        void insert(BSTNode*& root, BSTNode* node);
    
        /*先序遍历*/
        void preOrder(BSTNode* root);
    
        /*中序遍历*/
        void inOrder(BSTNode* root);
    
        /*后序遍历*/
        void postOrder(BSTNode* root);
    
        /*查找二叉树中键值为key的结点并返回*/
        BSTNode* search(BSTNode* node, int key);
    
        /*找出二叉树中键值最小的结点并返回*/
        BSTNode* minimum(BSTNode* node);
    
        /*找出二叉树中键值最大的结点并返回*/
        BSTNode* maximum(BSTNode* node);
    
        /*找到二叉树结点node的后继结点*/
        BSTNode* successor(BSTNode* node);
    
        /*找到二叉树结点node的前驱结点*/
        BSTNode* predecessor(BSTNode* node);
    
        /*移除键值为key的结点*/
        BSTNode* remove(BSTNode*& root, int key);
    
        /*销毁二叉排序树*/
        void destroy(BSTNode* root);
    };

    3、插入

    在二叉排序树进行插入操作时,每次插入的结点都是二叉排序树上新的叶子结点。可以将结点插入到一棵已经存在的二叉排序树上,也可以通过插入结点来构造一棵二叉排序树。

    /*
    * 将结点插入到二叉树中
    *
    * 参数说明:
    *     root 二叉树的根结点
    *     node 要插入的结点
    */
    void BSTree::insert(BSTNode*& root, BSTNode* node)
    {
        BSTNode* y = NULL;
        BSTNode* x = root;
    
        /*找到要插入的位置*/
        while (x != NULL)
        {
            y = x;
            if (node->key > x->key)
                x = x->right;
            else x = x->left;
        }
    
        /*插入结点*/
        node->parent = y;
        if (y == NULL)
            root = node;
        else if(y->key > node->key)
            y->left = node;
        else y->right = node;
    }
    
    void BSTree::insert(int key) 
    { BSTNode
    * node = new BSTNode(key, NULL, NULL, NULL); insert(root, node); }

    4、遍历

    二叉排序树的遍历同普通二叉树一样分为先序、中序、后序遍历,实现起来也没有差别。需要注意的是,中序遍历二叉排序树会得到一个关键字的有序序列。

    4.1 先序遍历

    /*先序遍历*/
    void BSTree::preOrder(BSTNode* root)
    {
        if (root != NULL)
        {
            cout << root->key;
            preOrder(root->left);
            preOrder(root->right);
        }
    }

    4.2 中序遍历

    中序遍历二叉排序树会得到一个关键字的有序序列。

    /*中序遍历*/
    void BSTree::inOrder(BSTNode* root)
    {
        if (root != NULL)
        {
            inOrder(root->left);
            cout << root->key;
            inOrder(root->right);
        }
    }

    4.3 后序遍历

    /*后序遍历*/
    void BSTree::postOrder(BSTNode* root)
    {
        if (root != NULL)
        {
            postOrder(root->left);
            postOrder(root->right);
            cout << root->key;
        }
    }

    5、查找

    当二叉树非空时,首先将待查找的键值与根节点的键值比较,若大于根节点的键值,则继续查找右子树,否则查找左子树。重复上述过程,直至查找成功返回找到的结点,否则返回空。

    BSTNode* BSTree::search(BSTNode* node, int key)
    {
        if (node == NULL || node->key == key)
            return node;
        if (node->key < key)
            search(node->right, key);
        else search(node->left, key);
    }

    6、最大值与最小值

    在一棵非空二叉排序树中,最小值结点为最左下结点,最大值结点为最右下结点。

    6.1 获取最小值结点

    BSTNode* BSTree::minimum(BSTNode* node)
    {
        if (node->left == NULL)
            return node;
        minimum(node->left);
    }

    6.2 获取最大值结点

    BSTNode* BSTree::maximum(BSTNode* node)
    {
        if (node->right == NULL)
            return node;
        maximum(node->right);
    }

    7、前驱结点与后继结点

    结点node的前驱结点是所有键值小于node的结点中的最大结点,也就是node的左子树的最大结点;

    结点node的后继结点是所有键值大于node的结点中的最小结点,也就是node的右子树的最小结点。

    7.1 前驱结点

    (1)若结点node的左子树非空,则左子树的最大结点即为node的前驱结点;

    (2)若结点node的左子树为空

      (2.1)若node为右孩子,则node的前驱结点为node的父结点;

      (2.2)若node为左孩子,则查找结点node的最低的父结点,且该父结点要有右孩子,此最低父结点即为node的前驱结点。

    /*查找结点node的前驱节点*/
    BSTNode* BSTree::predecessor(BSTNode* node)
    {
        /*(1)左子树非空,返回左子树最大值结点*/
        if (node->left != NULL)
            return maximum(node->left);
    
        /*(2)*/
        BSTNode* pnode = node->parent;
        while (pnode != NULL&&node == pnode->left)
        {
            node = pnode;
            pnode = pnode->parent;
        }
        return pnode;
    }

    7.2 后继结点

    (1)若结点node的右子树非空,则右子树的最小结点即为node的后继结点;

    (2)若结点node的右子树为空

      (2.1)若结点node为左孩子,则node的后继结点即为其父结点;

      (2.2)若结点node为右孩子,则查找node的最低的父结点,且该父结点要有左孩子,此最低父结点即为node的后继结点。

    /*查找node的后继结点*/
    BSTNode* BSTree::successor(BSTNode* node)
    {
        /*(1)右子树非空,返回右子树最小值结点*/
        if (node->right != NULL)
            return minimum(node->right);
    
        /*(2)*/
        BSTNode* pnode = node->parent;
        while (pnode != NULL&&node == pnode->right)
        {
            node = pnode;
            pnode = pnode->parent;
        }
        return pnode;
    }

     8、删除结点

    假设要删除的结点为*p(p为指向要删除结点的指针),其双亲结点为*f,不失一般性,可设*p是*f的左孩子。

    (1)若*p结点为叶子结点,即PL和PR均为空,则只需修改f->left为空即可;

    (2)若*p结点只有左子树PL或者只有右子树PR,这只需令PL和PR直接成为f的左孩子即可;

    (3)若*p结点的左子树和右子树均不为空,在删去*p之后,为保持其他元素之间的相对位置不变,可以有两种做法:

      (3.1)做法一:令*s为*p的左子树PL的最右结点,则令*p的左子树PL为*f的左子树,*p的右子树PR为*s的右子树;

      (3.2)做法二:令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删除它的直接前驱(或直接后继)。

    下面的代码当遇到情况(3)时,采用做法一:

    /*获取要删除的结点并返回*/
    BSTNode* BSTree::remove(BSTNode*& root, int key)
    {
        BSTNode* node = search(root, key);
        printf("%d
    ", node->key);
        if (node != NULL)
        {
            if (node->left == NULL && node->right == NULL)    //node为叶子结点
            {
                if (node->parent == NULL)    //要删除的结点为根结点
                    return node;
                else if (node->parent->left == node)//判断要删除点在双亲结点的左边还是右边
                    node->parent->left = NULL;
                else
                    node->parent->right = NULL;
            }
            else if (node->left == NULL)    //node左子树为空
            {
                if (node->parent == NULL)  //要删除的结点为根结点
                {
                    this->root = node->right;
                    node->right->parent = NULL;
                }
                else if (node->parent->left == node)//判断要删除点在双亲结点的左边还是右边
                    node->parent->left = node->right;
                else
                    node->parent->right = node->right;
            }
            else if (node->right == NULL)    //node右子树为空
            {
                if (node->parent == NULL)    //要删除的结点为根结点
                {
                    this->root = node->left;
                    node->left->parent = NULL;
                }
                else if (node->parent->left == node)//判断要删除点在双亲结点的左边还是右边
                    node->parent->left = node->left;
                else
                    node->parent->right = node->left;
            }
            else                            //node左右子树均不为空
            {
                BSTNode* lnode = node->left;    //lnode初始为node左子树的根节点
                while (lnode->right)            //找到node左子树的最右结点赋值为lnode
                    lnode = lnode->right;
                lnode->right = node->right;        //将node的右子树变成lnode的右子树
                node->right->parent = lnode;
                if (node->parent == NULL)   //要删除的结点为根结点
                {
                    this->root = node->right;
                    if (node->right->left != NULL)
                    {
                        BSTNode* leftDownNode = minimum(node->right);
                        leftDownNode->left = node->left;
                        node->left->parent = leftDownNode;
                    }
                    else
                    {
                        node->right->left = node->left;
                        node->left->parent = node->right;
                    }
                }
                else if (node->parent->left == node)    //将node的左子树替换node的位置
                {
                    node->parent->left = node->left;
                    node->left->parent = node->parent;
                }
                else if (node->parent->right == node)
                {
                    node->parent->right = node->left;
                    node->left->parent = node->parent;
                }
            }
        }
        return node;
    }

    9、销毁

    销毁二叉排序树与销毁普通二叉树没有区别,这里采用后序遍历的方式来销毁。

    /*销毁二叉树*/
    void BSTree::destroy(BSTNode* root)
    {
        if (root == NULL)
            return;
        destroy(root->left);
        destroy(root->right);
        delete root;
    }

     三、全部程序

    1、头文件bstree.h

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    class BSTNode {
    public:
        int key;            //结点的值
        BSTNode* left;        //结点的左孩子
        BSTNode* right;        //结点的右孩子
        BSTNode* parent;    //结点的双亲
    
        /*构造函数*/
        BSTNode():parent(NULL) {}
        BSTNode(int key, BSTNode* left, BSTNode* right, BSTNode* parent) :key(key), left(left), right(right), parent(parent) {}
    };
    
    class BSTree {
    private:
        BSTNode* root;        //根节点
    public:
        /*构造函数*/
        BSTree() :root(NULL) {};
    
        /*获取根节点*/
        BSTNode* getRoot();
    
        /*将键值key插入到二叉树中*/
        void insert(int key);
    
        /*将结点插入到二叉树中*/
        void insert(BSTNode*& root, BSTNode* node);
    
        /*先序遍历*/
        void preOrder(BSTNode* root);
    
        /*中序遍历*/
        void inOrder(BSTNode* root);
    
        /*后序遍历*/
        void postOrder(BSTNode* root);
    
        /*查找二叉树中键值为key的结点并返回*/
        BSTNode* search(BSTNode* node, int key);
    
        /*找出二叉树中键值最小的结点并返回*/
        BSTNode* minimum(BSTNode* node);
    
        /*找出二叉树中键值最大的结点并返回*/
        BSTNode* maximum(BSTNode* node);
    
        /*找到二叉树结点node的后继结点*/
        BSTNode* successor(BSTNode* node);
    
        /*找到二叉树结点node的前驱结点*/
        BSTNode* predecessor(BSTNode* node);
    
        /*移除键值为key的结点*/
        BSTNode* remove(BSTNode*& root, int key);
    
        /*销毁二叉排序树*/
        void destroy(BSTNode* root);
    };
    
    BSTNode* BSTree::getRoot()
    {
        return root;
    }
    
    /*先序遍历*/
    void BSTree::preOrder(BSTNode* root)
    {
        if (root != NULL)
        {
            cout << root->key;
            preOrder(root->left);
            preOrder(root->right);
        }
    }
    
    /*中序遍历*/
    void BSTree::inOrder(BSTNode* root)
    {
        if (root != NULL)
        {
            inOrder(root->left);
            cout << root->key;
            inOrder(root->right);
        }
    }
    
    /*后序遍历*/
    void BSTree::postOrder(BSTNode* root)
    {
        if (root != NULL)
        {
            postOrder(root->left);
            postOrder(root->right);
            cout << root->key;
        }
    }
    
    BSTNode* BSTree::search(BSTNode* node, int key)
    {
        if (node == NULL || node->key == key)
            return node;
        if (node->key < key)
            search(node->right, key);
        else search(node->left, key);
    }
    
    BSTNode* BSTree::minimum(BSTNode* node)
    {
        if (node->left == NULL)
            return node;
        minimum(node->left);
    }
    
    BSTNode* BSTree::maximum(BSTNode* node)
    {
        if (node->right == NULL)
            return node;
        maximum(node->right);
    }
    
    /*查找node的后继结点*/
    BSTNode* BSTree::successor(BSTNode* node)
    {
        /*(1)右子树非空,返回右子树最小值结点*/
        if (node->right != NULL)
            return minimum(node->right);
    
        /*(2)*/
        BSTNode* pnode = node->parent;
        while (pnode != NULL&&node == pnode->right)
        {
            node = pnode;
            pnode = pnode->parent;
        }
        return pnode;
    }
    
    /*查找结点node的前驱节点*/
    BSTNode* BSTree::predecessor(BSTNode* node)
    {
        /*(1)左子树非空,返回左子树最大值结点*/
        if (node->left != NULL)
            return maximum(node->left);
    
        /*(2)*/
        BSTNode* pnode = node->parent;
        while (pnode != NULL&&node == pnode->left)
        {
            node = pnode;
            pnode = pnode->parent;
        }
        return pnode;
    }
    
    /*
    * 将结点插入到二叉树中
    *
    * 参数说明:
    *     root 二叉树的根结点
    *     node 要插入的结点
    */
    void BSTree::insert(BSTNode*& root, BSTNode* node)
    {
        BSTNode* y = NULL;
        BSTNode* x = root;
    
        /*找到要插入的位置*/
        while (x != NULL)
        {
            y = x;
            if (node->key > x->key)
                x = x->right;
            else x = x->left;
        }
    
        /*插入结点*/
        node->parent = y;
        if (y == NULL)
            root = node;
        else if(y->key > node->key)
            y->left = node;
        else y->right = node;
    }
    
    void BSTree::insert(int key) {
        BSTNode* node = new BSTNode(key, NULL, NULL, NULL);
        insert(root, node);
    }
    
    //BSTNode* BSTree::remove(BSTNode*& root, int key)
    //{
    //    BSTNode* x = NULL;
    //    BSTNode* y = NULL;
    //
    //    BSTNode* z = search(root, key);
    //    if (z->left == NULL || z->right == NULL)
    //        y = z;
    //    else y = successor(z);
    //
    //    if (y->left != NULL)
    //        x = y->left;
    //    else x = y->right;
    //
    //    if (x != NULL)
    //        x->parent = y->parent;
    //
    //    if (y->parent == NULL)
    //        root = x;
    //    else if (y->parent->left == y)
    //        y->parent->left = x;
    //    else if (y->parent->right == y)
    //        y->parent->right = x;
    //
    //    if (y != z)
    //        z->key = y->key;
    //
    //    return y;
    //}
    
    /*获取要删除的结点并返回*/
    BSTNode* BSTree::remove(BSTNode*& root, int key)
    {
        BSTNode* node = search(root, key);
        printf("%d
    ", node->key);
        if (node != NULL)
        {
            if (node->left == NULL && node->right == NULL)    //node为叶子结点
            {
                if (node->parent == NULL)    //要删除的结点为根结点
                    return node;
                else if (node->parent->left == node)//判断要删除点在双亲结点的左边还是右边
                    node->parent->left = NULL;
                else
                    node->parent->right = NULL;
            }
            else if (node->left == NULL)    //node左子树为空
            {
                if (node->parent == NULL)  //要删除的结点为根结点
                {
                    this->root = node->right;
                    node->right->parent = NULL;
                }
                else if (node->parent->left == node)//判断要删除点在双亲结点的左边还是右边
                    node->parent->left = node->right;
                else
                    node->parent->right = node->right;
            }
            else if (node->right == NULL)    //node右子树为空
            {
                if (node->parent == NULL)    //要删除的结点为根结点
                {
                    this->root = node->left;
                    node->left->parent = NULL;
                }
                else if (node->parent->left == node)//判断要删除点在双亲结点的左边还是右边
                    node->parent->left = node->left;
                else
                    node->parent->right = node->left;
            }
            else                            //node左右子树均不为空
            {
                BSTNode* lnode = node->left;    //lnode初始为node左子树的根节点
                while (lnode->right)            //找到node左子树的最右结点赋值为lnode
                    lnode = lnode->right;
                lnode->right = node->right;        //将node的右子树变成lnode的右子树
                node->right->parent = lnode;
                if (node->parent == NULL)   //要删除的结点为根结点
                {
                    this->root = node->right;
                    if (node->right->left != NULL)
                    {
                        BSTNode* leftDownNode = minimum(node->right);
                        leftDownNode->left = node->left;
                        node->left->parent = leftDownNode;
                    }
                    else
                    {
                        node->right->left = node->left;
                        node->left->parent = node->right;
                    }
                }
                else if (node->parent->left == node)    //将node的左子树替换node的位置
                {
                    node->parent->left = node->left;
                    node->left->parent = node->parent;
                }
                else if (node->parent->right == node)
                {
                    node->parent->right = node->left;
                    node->left->parent = node->parent;
                }
            }
        }
        return node;
    }
    
    /*销毁二叉树*/
    void BSTree::destroy(BSTNode* root)
    {
        if (root == NULL)
            return;
        destroy(root->left);
        destroy(root->right);
        delete root;
    }
    View Code

    2、测试文件bstree.cpp

     1 #include "bstree.h"
     2 
     3 int main()
     4 {
     5     int a[] = { 1, 5, 4, 3, 2, 6 };
     6     
     7     BSTree* tree = new BSTree();
     8     for (int i = 0; i < 6;i++)
     9         tree->insert(a[i]);
    10     
    11     cout << "先序遍历:";
    12     tree->preOrder(tree->getRoot());
    13     cout << endl;
    14     
    15     cout << "中序遍历:";
    16     tree->inOrder(tree->getRoot());
    17     cout << endl;
    18 
    19     cout << "后序遍历:";
    20     tree->postOrder(tree->getRoot());
    21     cout << endl;
    22 
    23     cout << "最小值:";
    24     BSTNode* minNode = tree->minimum(tree->getRoot());
    25     if(minNode != NULL)
    26         cout << minNode->key << endl;
    27 
    28     cout << "最大值:";
    29     BSTNode* maxNode = tree->maximum(tree->getRoot());
    30     if (maxNode != NULL)
    31         cout << maxNode->key << endl;
    32 
    33 
    34     BSTNode* node = tree->search(tree->getRoot(), 6);
    35     BSTNode* snode = tree->successor(node);
    36     if (snode != NULL)
    37         cout << snode->key << endl;
    38 
    39     BSTNode* pnode = tree->predecessor(node);
    40     if (pnode != NULL)
    41         cout << pnode->key << endl;
    42 
    43     BSTNode* root = tree->getRoot();
    44     BSTNode* dnode = tree->remove(root, 5);
    45     cout << "删除" << dnode->key << "后先序遍历:" << endl;
    46     if (dnode) delete dnode;
    47     tree->preOrder(tree->getRoot());
    48     cout << endl;
    49 
    50     cout << "销毁二叉树" << endl;
    51     tree->destroy(root);
    52 }

    3、结果

    先序遍历:154326
    中序遍历:123456
    后序遍历:234651
    最小值:1
    最大值:6
    5
    删除5后先序遍历:
    14326
    销毁二叉树

    四、参考

    1、http://www.cnblogs.com/skywang12345/p/3576373.html

    2、 严蔚敏、吴伟民《数据结构》

  • 相关阅读:
    Linux Enterprise Cluster NOtes Ch4 同步:ssh和rsync
    e805上不安装中文外挂支持中文,很简单而且实用
    ARM的一些概念性问题
    C#调用WORD处理的小项目 转
    ASP.NET面试题
    .net清除cookie代码|.net为什么不能清除cookie|.net cookie 过期代码
    c#字符串转数字的函数|c#字符串转数字的无错函数|c#字符串转数字的最好函数
    Wiki简介
    new 和override 重写区别
    禁用IE的后退按钮|显示网页已过期|几种语言的实现方法|c#|javascript|html
  • 原文地址:https://www.cnblogs.com/sench/p/7783331.html
Copyright © 2020-2023  润新知