二叉排序樹


一、定義

二叉排序樹,又叫二叉查找樹,它或者是一棵空樹;或者是具有以下性質的二叉樹:
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、 嚴蔚敏、吳偉民《數據結構》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM