二叉排序树

一、定义

二叉排序树,又叫二叉查找树,它或者是一棵空树;或者是具有以下性质的二叉树:
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\n", 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\n", 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、 严蔚敏、吴伟民《数据结构》

posted @ 2017-11-04 14:36  ColdCode  阅读(37744)  评论(3编辑  收藏  举报
AmazingCounters.com