码迷,mamicode.com
首页 > 编程语言 > 详细

算法导论第十二章 二叉搜索树

时间:2015-10-20 22:53:17      阅读:369      评论:0      收藏:0      [点我收藏+]

标签:

一、二叉搜索树概览

  二叉搜索树(又名二叉查找树、二叉排序树)是一种可提供良好搜寻效率的树形结构,支持动态集合操作,所谓动态集合操作,就是Search、Maximum、Minimum、Insert、Delete等操作,二叉搜索树可以保证这些操作在对数时间内完成。当然,在最坏情况下,即所有节点形成一种链式树结构,则需要O(n)时间。这就说明,针对这些动态集合操作,二叉搜索树还有改进的空间,即确保最坏情况下所有操作在对数时间内完成。这样的改进结构有AVL(Adelson-Velskii-Landis) tree、RB(红黑)tree和AA-tree。AVL树和红黑树相对应用较多,我们在后面的章节中在做整理。

  在二叉搜索树中,任何一个节点的键值一定大于其左子树中的每一个节点的键值,并小于其右子树中每一个节点的键值。我们结合书本的理论对二叉搜索树的动态集合操作做编程实现。其中除了Delete操作稍稍复杂之外,其余的操作都是非常简单的。

二、二叉搜索树动态集合操作

1、查询二叉搜索树

  查询包括查找某一个元素,查找最大、最小关键字元素,查找前驱和后继,根据二叉搜索树的性质:左子树 < 根 < 右子树,这样的操作很容易实现。如下:

查找某元素:

 1 //@brief 查找元素
 2 //@return 是否查找成功
 3 bool BinarySearchTree::Search(const int search_value) const
 4 {
 5     return _Search(m_pRoot, search_value) != NULL;
 6 }
 7 
 8 //@brief 真正的查找操作
 9 //非递归查找
10 BinarySearchTree::_Node * BinarySearchTree::_Search(_Node *node, const int search_value) const
11 {
12     //递归
13 //     if (node == NULL || search_value = node->m_nValue)
14 //         return node;
15 //     if (search_value < node->m_nValue)
16 //         return _Search(node->m_pLeft);
17 //     else
18 //         return _Search(node->m_pRight);
19 
20     //非递归
21     while(node && search_value != node->m_nValue) {
22         if (search_value < node->m_nValue)
23             node = node->m_pLeft;
24         else
25             node = node->m_pRight;
26     }
27     return node;
28 }

 

查找最大、最小关键字元素:

 1 //@brief 得到以node为根节点的子树中的最大关键字节点
 2 BinarySearchTree::_Node * BinarySearchTree::_GetMaximum(_Node *node) const
 3 {
 4     while(node->m_pRight) {
 5         node = node->m_pRight;
 6     }
 7     return node;
 8 }
 9 
10 //@brief 得到以node为根节点的子树中的最小关键字节点
11 BinarySearchTree::_Node * BinarySearchTree::_GetMinimum(_Node *node) const
12 {
13     while(node->m_pLeft) {
14         node = node->m_pLeft;
15     }
16     return node;
17 }

 

查找前驱和后继:

 1 //@brief 得到一个同时存在左右子树的节点node的前驱
 2 BinarySearchTree::_Node * BinarySearchTree::_GetPredecessor(_Node *node) const
 3 {
 4     if (node->m_pLeft)
 5         return _GetMinimum(node);
 6 
 7     _Node *pTemp = node->m_pParent;
 8     while (pTemp && node == pTemp->m_pLeft) {
 9         node = pTemp;
10         pTemp = pTemp->m_pParent;
11     }
12     return pTemp;
13 }
14 
15 //@brief 得到一个同时存在左右子树的节点node的后继
16 BinarySearchTree::_Node * BinarySearchTree::_GetSuccessor(_Node *node) const
17 {
18     if(node->m_pRight)
19         return _GetMaximum(node);
20 
21     _Node *pTemp = node->m_pParent;
22     while (pTemp && node == pTemp->m_pRight ) {
23         node = pTemp;
24         pTemp = pTemp->m_pParent;
25     }
26     return pTemp;
27 }

 

2、插入和删除

插入操作:通过不断的遍历,找到待插入元素应该处的位置,即可进行插入,代码如下:包括递归和非递归的版本:

 1 //@brief 插入元素
 2 //@return 是否插入成功
 3 bool BinarySearchTree::Insert(const int new_value)
 4 {
 5     //非递归
 6     if (Search(new_value))
 7         return false;
 8 
 9     _Node *pTemp = NULL;
10     _Node *pCurrent = m_pRoot;
11     while ( pCurrent ) {
12         pTemp = pCurrent;
13         if ( new_value < pCurrent->m_nValue )
14             pCurrent = pCurrent->m_pLeft;
15         else
16             pCurrent = pCurrent->m_pRight;
17 
18     }
19     _Node *pInsert = new _Node();
20     pInsert->m_nValue = new_value;
21     pInsert->m_pParent = pTemp;
22 
23     if ( !pTemp ) //空树
24         m_pRoot = pInsert;
25     else if ( new_value < pTemp->m_nValue ) 
26         pTemp->m_pLeft = pInsert;
27     else
28         pTemp->m_pRight = pInsert;
29     return true;
30 }
31 
32 //递归
33 BinarySearchTree::_Node * BinarySearchTree::Insert_Recur(_Node *&node, const int new_value)
34 {
35     if ( node == NULL ) {
36         _Node *pInsert = new _Node();
37         pInsert->m_nValue = new_value;
38         node = pInsert;
39     }
40     else if ( new_value < node->m_nValue )
41         node->m_pLeft = Insert_Recur( node->m_pLeft, new_value );
42     else
43         node->m_pRight = Insert_Recur( node->m_pRight, new_value );
44     return node;
45 }

 

删除操作:有点小复杂,总共分为四种情况:

1)如果待删除节点没有子节点,则直接删除即可,并更改其父节点的指向;

2)如果待删除的节点只有一个子节点,其中,如果为左子树节点,则用左子树节点替换之;反之用右子树节点替换之;

3)如果待删除节点 z 有两个子节点,这个时候分两种情况考虑,第一种情况:z 的后继即为 z 的右孩子节点,则将 z 的有孩子节点替换之;

4)第二种情况: z 的后继不是 z 的有孩子节点,则首先用 z 的后继的有孩子节点替换 z 的后继,再用 z 的后继替换 z 。

没有图形作为辅助,实属难以表述和透彻理解,详细的过程和分析见书本上。

注意:在《算法导论》前几版的实现中,该过程的实现略有不同,相较上面这个过程,要简单一些,做法是:不是用 z 的后继 y 替换节点 z,而是删除节点 y,但复制 y 的关键字到节点 z 中来实现。但是这种做法,作者在最新这一版中明确提出,那种方法的缺陷是:会造成实际被删除的节点并不是被传递到删除过程中的那个节点,会有一些已删除节点的“过时”指针带来不必要的影响,总之复制删除的方法不是好的。代码实现如下:

//@brief 删除元素
//@return 是否删除成功
bool BinarySearchTree::Delete(const int delete_value)
{
    _Node *delete_node = _Search(m_pRoot, delete_value);
    
    //未找到该节点
    if (!delete_node)
        return false;
    else {
        _DeleteNode(delete_node);
        return true;
    }
}

//@brief 真正的删除操作
void BinarySearchTree::_DeleteNode(_Node *delete_node)
{
    if (delete_node->m_pLeft == NULL)
        _Delete_Transplant(delete_node, delete_node->m_pRight);
    else if (delete_node->m_pRight == NULL)
        _Delete_Transplant(delete_node, delete_node->m_pLeft);
    else {
        _Node *min_node = _GetMinimum(delete_node->m_pRight);
        if (min_node->m_pParent != delete_node) {
            _Delete_Transplant(min_node, min_node->m_pRight);
            min_node->m_pRight = delete_node->m_pRight;
            min_node->m_pRight->m_pParent = min_node;
        }
        _Delete_Transplant(delete_node, min_node);
        min_node->m_pLeft = delete_node->m_pLeft;
        min_node->m_pLeft->m_pParent = min_node;
    }
}

void BinarySearchTree::_Delete_Transplant(_Node *unode, _Node *vnode)
{
    if (unode->m_pParent == NULL)
        m_pRoot = vnode;
    else if (unode == unode->m_pParent->m_pLeft)
        unode->m_pParent->m_pLeft = vnode;
    else
        unode->m_pParent->m_pRight = vnode;
    if (vnode)
        vnode->m_pParent = unode->m_pParent;
}

这里增加了一个函数Transplant()来实现替换操作,使代码较简洁。

完整的代码如下:

技术分享
//BinarySearchTree.h

#ifndef _BINARY_SEARCH_TREE_
#define _BINARY_SEARCH_TREE_

class BinarySearchTree 
{
private:
    struct _Node {
        int        m_nValue;
        _Node    *m_pParent;
        _Node    *m_pLeft;
        _Node    *m_pRight;
    };

public:
    BinarySearchTree(_Node *pRoot = NULL):m_pRoot(pRoot){}

    ~BinarySearchTree();

    //@brief 插入元素
    //@return 是否插入成功
    bool Insert(const int new_value);

    //递归
    _Node * Insert_Recur(_Node *&node, const int new_value);

    //@brief 删除元素
    //@return 是否删除成功
    bool Delete(const int delete_value);

    //@brief 查找元素
    //@return 是否查找成功
    bool Search(const int search_value) const;

    //@brief 使用dot描述当前二叉查找树
    void Display() const;
    
    //@brief 树的遍历
    void Inorder() const {Inorder_Tree_Walk(m_pRoot);}
    void Preorder() const {Preorder_Tree_Walk(m_pRoot);}
    void Postorder() const {Postorder_Tree_Walk(m_pRoot);}
    

private:
    //@brief 真正的删除操作
    void _DeleteNode(_Node *delete_node);
    void _Delete_Transplant(_Node *unode, _Node *vnode);

    //@brief 得到以node为根节点的子树中的最大关键字节点
    _Node * _GetMaximum(_Node *node) const;

    //@brief 得到以node为根节点的子树中的最小关键字节点
    _Node * _GetMinimum(_Node *node) const;

    //@brief 得到一个同时存在左右子树的节点node的前驱
    _Node * _GetPredecessor(_Node *node) const;

    //@brief 得到一个同时存在左右子树的节点node的后继
    _Node * _GetSuccessor(_Node *node) const;

    //@brief 真正的查找操作
    //非递归查找
    _Node * _Search(_Node *node, const int search_value) const;

    //@brief 显示一棵二叉搜索树
    void _Display(/*iostream &ss, */_Node *node) const;

    //@brief 递归释放节点
    void _RecursiveReleaseNode(_Node *node);

    void ShowGraphvizViaDot(const string &dot) const;

    //@brief 树的遍历
    void Inorder_Tree_Walk(_Node *node) const;
    void Preorder_Tree_Walk(_Node *node) const;
    void Postorder_Tree_Walk(_Node *node) const;

private:
    _Node    *m_pRoot;
};

#endif//_BINARY_SEARCH_TREE_

//BinarySearchTree.cpp
#include <iostream>
#include <string>
#include <iomanip>
#include <ctime>

using namespace std;

#include "BinarySearchTree.h"

BinarySearchTree::~BinarySearchTree()
{
    _RecursiveReleaseNode(m_pRoot);
}

//@brief 插入元素
//@return 是否插入成功
bool BinarySearchTree::Insert(const int new_value)
{
    //非递归
    if (Search(new_value))
        return false;

    _Node *pTemp = NULL;
    _Node *pCurrent = m_pRoot;
    while ( pCurrent ) {
        pTemp = pCurrent;
        if ( new_value < pCurrent->m_nValue )
            pCurrent = pCurrent->m_pLeft;
        else
            pCurrent = pCurrent->m_pRight;

    }
    _Node *pInsert = new _Node();
    pInsert->m_nValue = new_value;
    pInsert->m_pParent = pTemp;

    if ( !pTemp ) //空树
        m_pRoot = pInsert;
    else if ( new_value < pTemp->m_nValue ) 
        pTemp->m_pLeft = pInsert;
    else
        pTemp->m_pRight = pInsert;
    return true;


//     //该元素已经存在
//     if (Search(new_value))
//         return false;
//     
//     //空树,插入第1个节点
//     if (!m_pRoot) {
//         m_pRoot = new _Node();
//         m_pRoot->m_nValue = new_value;
//         return true;
//     }
// 
//     //非第一个节点
//     _Node *current_node = m_pRoot;
//     while( current_node ) {
//         _Node *&next_node_pointer = (new_value < current_node->m_nValue ? current_node->m_pLeft:current_node->m_pRight);
//         if ( next_node_pointer )
//             current_node = next_node_pointer;
//         else {
//             next_node_pointer = new _Node();
//             next_node_pointer->m_nValue = new_value;
//             next_node_pointer->m_pParent = current_node;
//             break;
//         }
//     }
//     return true;
}

//递归
BinarySearchTree::_Node * BinarySearchTree::Insert_Recur(_Node *&node, const int new_value)
{
    if ( node == NULL ) {
        _Node *pInsert = new _Node();
        pInsert->m_nValue = new_value;
        node = pInsert;
    }
    else if ( new_value < node->m_nValue )
        node->m_pLeft = Insert_Recur( node->m_pLeft, new_value );
    else
        node->m_pRight = Insert_Recur( node->m_pRight, new_value );
    return node;
}

//@brief 删除元素
//@return 是否删除成功
bool BinarySearchTree::Delete(const int delete_value)
{
    _Node *delete_node = _Search(m_pRoot, delete_value);
    
    //未找到该节点
    if (!delete_node)
        return false;
    else {
        _DeleteNode(delete_node);
        return true;
    }
}

//@brief 查找元素
//@return 是否查找成功
bool BinarySearchTree::Search(const int search_value) const
{
    return _Search(m_pRoot, search_value) != NULL;
}

//@brief 使用dot描述当前二叉查找树
void BinarySearchTree::Display() const
{
    _Display(m_pRoot);
}

//@brief 树的遍历
//中序
void BinarySearchTree::Inorder_Tree_Walk(_Node *node) const
{
    if (node) {
        Inorder_Tree_Walk(node->m_pLeft);
        cout << node->m_nValue << " ";
        Inorder_Tree_Walk(node->m_pRight);
    }
}

//前序
void BinarySearchTree::Preorder_Tree_Walk(_Node *node) const
{
    if (node) {
        cout << node->m_nValue << " ";
        Preorder_Tree_Walk(node->m_pLeft);
        Preorder_Tree_Walk(node->m_pRight);
    }
}

//后序
void BinarySearchTree::Postorder_Tree_Walk(_Node *node) const
{
    if (node) {
        Postorder_Tree_Walk(node->m_pLeft);
        Postorder_Tree_Walk(node->m_pRight);
        cout << node->m_nValue << " ";
    }
}

//@brief 真正的删除操作
void BinarySearchTree::_DeleteNode(_Node *delete_node)
{
    if (delete_node->m_pLeft == NULL)
        _Delete_Transplant(delete_node, delete_node->m_pRight);
    else if (delete_node->m_pRight == NULL)
        _Delete_Transplant(delete_node, delete_node->m_pLeft);
    else {
        _Node *min_node = _GetMinimum(delete_node->m_pRight);
        if (min_node->m_pParent != delete_node) {
            _Delete_Transplant(min_node, min_node->m_pRight);
            min_node->m_pRight = delete_node->m_pRight;
            min_node->m_pRight->m_pParent = min_node;
        }
        _Delete_Transplant(delete_node, min_node);
        min_node->m_pLeft = delete_node->m_pLeft;
        min_node->m_pLeft->m_pParent = min_node;
    }
}

void BinarySearchTree::_Delete_Transplant(_Node *unode, _Node *vnode)
{
    if (unode->m_pParent == NULL)
        m_pRoot = vnode;
    else if (unode == unode->m_pParent->m_pLeft)
        unode->m_pParent->m_pLeft = vnode;
    else
        unode->m_pParent->m_pRight = vnode;
    if (vnode)
        vnode->m_pParent = unode->m_pParent;
}

//@brief 得到以node为根节点的子树中的最大关键字节点
BinarySearchTree::_Node * BinarySearchTree::_GetMaximum(_Node *node) const
{
    while(node->m_pRight) {
        node = node->m_pRight;
    }
    return node;
}

//@brief 得到以node为根节点的子树中的最小关键字节点
BinarySearchTree::_Node * BinarySearchTree::_GetMinimum(_Node *node) const
{
    while(node->m_pLeft) {
        node = node->m_pLeft;
    }
    return node;
}

//@brief 得到一个同时存在左右子树的节点node的前驱
BinarySearchTree::_Node * BinarySearchTree::_GetPredecessor(_Node *node) const
{
    if (node->m_pLeft)
        return _GetMinimum(node);

    _Node *pTemp = node->m_pParent;
    while (pTemp && node == pTemp->m_pLeft) {
        node = pTemp;
        pTemp = pTemp->m_pParent;
    }
    return pTemp;
}

//@brief 得到一个同时存在左右子树的节点node的后继
BinarySearchTree::_Node * BinarySearchTree::_GetSuccessor(_Node *node) const
{
    if(node->m_pRight)
        return _GetMaximum(node);

    _Node *pTemp = node->m_pParent;
    while (pTemp && node == pTemp->m_pRight ) {
        node = pTemp;
        pTemp = pTemp->m_pParent;
    }
    return pTemp;
}

//@brief 真正的查找操作
//非递归查找
BinarySearchTree::_Node * BinarySearchTree::_Search(_Node *node, const int search_value) const
{
    //递归
//     if (node == NULL || search_value = node->m_nValue)
//         return node;
//     if (search_value < node->m_nValue)
//         return _Search(node->m_pLeft);
//     else
//         return _Search(node->m_pRight);

    //非递归
    while(node && search_value != node->m_nValue) {
        if (search_value < node->m_nValue)
            node = node->m_pLeft;
        else
            node = node->m_pRight;
    }
    return node;
}

//@brief 显示一棵二叉搜索树
void BinarySearchTree::_Display(/*iostream &ss, */_Node *node) const
{
    if ( node )
    {
        cout << node->m_nValue << " ";

        if ( node->m_pLeft )
        {
            _Display( node->m_pLeft );
        }

        if ( node->m_pRight )
        {
            _Display( node->m_pRight );
        }
    }
}

//@brief 递归释放节点
void BinarySearchTree::_RecursiveReleaseNode(_Node *node)
{
    if (node) {
        _RecursiveReleaseNode(node->m_pLeft);
        _RecursiveReleaseNode(node->m_pRight);
        delete node;
    }
}


int main()
{
    srand((unsigned)time(NULL));
    BinarySearchTree bst;

    //用随机值生成一棵二叉查找树
    for (int i= 0; i < 10; i ++) {
        bst.Insert( rand() % 100 ); 
    }

    bst.Display();
    cout << endl;

    //中序遍历
//     bst.Inorder();
//     cout << endl;


    //删除所有的奇数值结点
    for ( int i = 1; i < 100; i += 2 )
    {
        if( bst.Delete( i ) )
        {
            cout << "### Deleted [" << i << "] ###" << endl;
        }
    }
    //验证删除的交换性
//     bst.Delete(2);
//     bst.Delete(1);
//     bst.Display();
//     cout << endl;


    //查找100以内的数,如果在二叉查找树中,则显示
    cout << endl;
    for ( int i = 0; i < 10; i += 1 )
    {
        if ( bst.Search( i ) )
        {
            cout << "搜索[" << i << "]元素:\t成功" << endl;
        }
    }
    
    cout << endl;
    //中序遍历
    bst.Inorder();
    return 0;
}
View Code

 

算法导论第十二章 二叉搜索树

标签:

原文地址:http://www.cnblogs.com/bakari/p/4892558.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!