二叉排序樹

1、定義html

二叉排序樹,又叫二叉查找樹,它或者是一棵空樹;或者是具備如下性質的二叉樹:
1. 若它的左子樹不空,則左子樹上全部節點的值均小於它的根節點的值;
2. 若它的右子樹不空,則右子樹上全部節點的值均大於它的根節點的值;
3. 它的左右子樹也分別爲二叉排序樹。node

以下圖所示:ios

 2、二叉排序樹的C++實現數據結構

一、結點定義ide

爲簡單起見,這裏將結點的鍵值類型設爲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) {}
};

 

 二、二叉排序樹的各類操做post

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);
};

三、插入測試

在二叉排序樹進行插入操做時,每次插入的結點都是二叉排序樹上新的葉子結點。能夠將結點插入到一棵已經存在的二叉排序樹上,也能夠經過插入結點來構造一棵二叉排序樹。this

/*
* 將結點插入到二叉樹中
*
* 參數說明:
*     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); }

四、遍歷spa

二叉排序樹的遍歷同普通二叉樹同樣分爲先序、中序、後序遍歷,實現起來也沒有差異。須要注意的是,中序遍歷二叉排序樹會獲得一個關鍵字的有序序列。

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;
    }
}

五、查找

當二叉樹非空時,首先將待查找的鍵值與根節點的鍵值比較,若大於根節點的鍵值,則繼續查找右子樹,不然查找左子樹。重複上述過程,直至查找成功返回找到的結點,不然返回空。

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.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);
}

七、前驅結點與後繼結點

結點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;
}

 八、刪除結點

假設要刪除的結點爲*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;
}

九、銷燬

銷燬二叉排序樹與銷燬普通二叉樹沒有區別,這裏採用後序遍歷的方式來銷燬。

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

 3、所有程序

一、頭文件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

二、測試文件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 }

三、結果

先序遍歷:154326
中序遍歷:123456
後序遍歷:234651
最小值:1
最大值:6
5
刪除5後先序遍歷:
14326
銷燬二叉樹

4、參考

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

二、 嚴蔚敏、吳偉民《數據結構》

相關文章
相關標籤/搜索