二叉搜索树

       二叉树的一个重要应用就是在查找中,假设树中每一个结点的数据域存储一定的数据信息,按照一定的规则就能处理这些信息。二叉搜索树是一种特殊的二叉树,对于任意一个结点,它的所有左子树结点项的值都小于其节点值,而它的所有右字数的结点的值都大于其结点值。在下图中,左边的数是二叉搜索树,而右边不是,因为其项值是6的结点在其左字数中存在项值为7的结点,不满足任意节点左子树的值小于其值。
二叉搜索树 - system404 - system404
 
和其他很多树的实现一样,二叉搜索树也是通过递归实现的,下面是二叉搜索树C++模板类的主要接口。
template<typename T>
class BSTree{
public:
    BSTree():root(NULL),currSize(0){};//默认构造函数
    explicit BSTree(std::vector<T> &);//从一个数据系列中读入数据构造
    BSTree(const BSTree &rhs):root(NULL),currSize(0){*this = rhs;}
    BSTree &operator=(const BSTree &);
    ~BSTree();

    T &max() const; //返回最大值
    T &min() const; //返回最小值
    bool contains(const T &)const;  //判断是否包含某项
    bool isEmpty() const; //判断树空
    size_t size() const; //返回当前树的有效大小
    void print(std::ostream &out = std::cout)const;//打印数结点信息

    void clear(); //清空树
    void insert(const T &);//插入一个结点
    void remove(const T &);//删除一个结点
private:
    struct Node{ //二叉搜索树的结点结构
        T data; //数据域
        Node *lchild; //左孩子
        Node *rchild; //右孩子
        Node(const T &val,Node *left =NULL,Node *right =NULL):data(val),lchild(left),rchild(right){}
    };
    Node *root;
    size_t currSize;

    void insert(Node **tree,const T &val);//在树tree中插入一个结点
    void remove(Node **tree,const T &val);//从树tree中移除一个结点
    Node *max(Node *tree) const;  //返回树tree最大项的指针
    Node *min(Node *tree) const;  //返回树tree最小项的指针
    bool contains(Node *tree,const T &val)const;//判断树tree是否包含某项
    void clear(Node **tree); //清空树tree
    void print(Node *,std::ostream &)const;//打印树tree
    Node *clone(Node *tree) const;  //复制树tree
};

数据成员root为指向树根结点的指针,当数空时root为NULL,public接口调用对应的私有成员函数实现指定的功能。对于二叉搜索树的插入,从根结点开始查找,如果插入项小于当前结点的值,则继续往左走,如果插入项大于当前结点的值,则往又走,如果等于当前节点值,则什么都不做或者做相应的更新操作。如下图所示,为了插入5,从根结点6开始遍历,5比6小,则往根结点的左子树走。到大结点2时,5比2大,往右走,在结点4处,继续往又走,但是4不存在右子树,所以此处就是要插入的位置。
二叉搜索树 - system404 - system404
插入5以前和插入5以后的二叉搜索树

下面是插入结点的实现:

void insert(Node **tree,const T &val){
    if(NULL == *tree)
        *tree = new Node(val);//树空则生成一个结点
    else if(val < (*tree)->data)//左递归
        insert(&(*tree)->lchild,val);
    else if(val > (*tree)->data)//右递归
        insert(&(*tree)->rchild,val);
    else{ //树中已经存在结点和待插入的值一样
        /* You can do something here*/
    }
}

相对于插入操作,删除操作则相对要复杂一些,一旦找到要删除的目标结点,则可能有多种情况:
如果待删除结点是一个叶子结点,则可以直接删除,如果待删除结点有一个儿子,则该结点也可以在简单的调整后删除,如下图所示:

二叉搜索树 - system404 - system404
删除结点4前后的二叉搜索树

如果待删除结点有两个儿子,一般的删除策略是用其右子树的最小结点代替待删除结点的数据,然后递归删除那个右子树最小结点。如下图所示,要删除结点2,则找到结点2的右子树的最小结点3并将其数据赋值给结点2,然后在删除结点3。
二叉搜索树 - system404 - system404
删除结点2前后的二叉树

删除结点的代码实现:

void remove(Node **tree,const T &val){
    if(NULL == *tree)return;
    
    if(val < (*tree)->data)
        remove(&(*tree)->lchild,val);
    else if(val > (*tree)->data)
        remove(&(*tree)->rchild,val);
    else if(NULL != (*tree)->lchild &&NULL != (*tree)->rchild){//待删除结点有两个儿子
        (*tree)->data = min((*tree)->rchild)->data; //将待删除结点的值赋值为其右子树的最小值
        remove(&(*tree)->rchild,(*tree)->data); //递归删除待删除结点的右子树最小结点
    }else{ //找到待删除结点
        Node *delNode = *tree; 
        *tree = ((*tree)->lchild != NULL) ? (*tree)->lchild : (*tree)->rchild;
        delete delNode;
    }
}


代码实现和测试:

/*
 * File: BinarySearchTree.hpp
 * User: wqy
 * CreateTime: 2013-02-20 21:22
 * ModifyTime: 2013-02-20 21:57
 */

#ifndef BINARYSEARCHTREE_H
#define BINARYSEARCHTREE_H
#include <iostream>
#include <vector>
#include <iterator>

template<typename T>
class BSTree{
public:
    BSTree():root(NULL),currSize(0){};
	explicit BSTree(std::vector<T> &);
    BSTree(const BSTree &rhs):root(NULL),currSize(0){*this = rhs;}
    BSTree &operator=(const BSTree &);
    ~BSTree();

    T &max() const;
    T &min() const;
    bool contains(const T &) const;
    bool isEmpty() const;
	size_t size() const;
    void print(std::ostream &out = std::cout) const;

    void clear();
    void insert(const T &);
    void remove(const T &);
private:
    struct Node{
        T data;
        Node *lchild;
        Node *rchild;
        Node(const T &val,Node *left = NULL,Node *right = NULL):data(val),lchild(left),rchild(right){}
    };
    Node *root;
	size_t currSize;

    void insert(Node **tree,const T &val);
    void remove(Node **tree,const T &val);
    Node *max(Node *tree) const;
    Node *min(Node *tree) const;
    bool contains(Node *tree,const T &val) const;
    void clear(Node **tree);
    void print(Node *,std::ostream &) const;
    Node *clone(Node *tree) const;
};

template<typename T>
BSTree<T>::BSTree(std::vector<T> &items):root(NULL),currSize(0){
	typename std::vector<T>::iterator iter = items.begin();
	while(iter != items.end())
		insert(*iter++);
}

template<typename T>
BSTree<T>::~BSTree(){
    clear();
}

template<typename T>
BSTree<T> &BSTree<T>::operator=(const BSTree<T> &rhs){
    if(this != &rhs){
        clear();
        root = clone(rhs.root);
		currSize = rhs.size();
    }
    return *this;
}

template<typename T>
inline T &BSTree<T>::max() const{
    if(!root)
        throw std::exception();
    return max(root)->data;
}

template<typename T>
inline T &BSTree<T>::min() const{
    if(!root)
        throw std::exception();
    return min(root)->data;
}

template<typename T>
inline bool BSTree<T>::contains(const T &val) const{
    return contains(root,val);
}

template<typename T>
inline bool BSTree<T>::isEmpty() const{
    return NULL == root;
}

template<typename T>
inline size_t BSTree<T>::size() const{
	return currSize;
}

template<typename T>
void BSTree<T>::print(std::ostream &out) const{
    print(root,out);
}

template<typename T>
void BSTree<T>::clear(){
    clear(&root);
	currSize = 0;
}

template<typename T>
void BSTree<T>::insert(const T &val){
	if(contains(val)) return;
    insert(&root,val);
	++currSize;
}

template<typename T>
void BSTree<T>::remove(const T &val){
    if(!contains(val))
        throw std::exception();
    remove(&root,val);
	--currSize;
}

template<typename T>
void BSTree<T>::insert(Node **tree,const T &val){
    if(NULL == *tree)
        *tree = new Node(val);
    else if(val < (*tree)->data)
        insert(&(*tree)->lchild,val);
    else if(val > (*tree)->data)
        insert(&(*tree)->rchild,val);
    else{
        /* You can do something here */
    }
}

template<typename T>
void BSTree<T>::remove(Node **tree,const T &val){
    if(NULL == *tree) return;
    
    if(val < (*tree)->data)
        remove(&(*tree)->lchild,val);
    else if(val > (*tree)->data)
        remove(&(*tree)->rchild,val);
    else if(NULL != (*tree)->lchild && NULL != (*tree)->rchild){
        (*tree)->data = min((*tree)->rchild)->data;
        remove(&(*tree)->rchild,(*tree)->data);
    }else{
        Node *delNode = *tree;
        *tree = ((*tree)->lchild != NULL) ? (*tree)->lchild : (*tree)->rchild;
        delete delNode; 
    }
}

template<typename T>
inline typename BSTree<T>::Node *BSTree<T>::max(Node *tree) const{
    if(NULL == tree)
        return NULL;
    if(NULL == tree->rchild)
        return tree;
    return max(tree->rchild);
}

template<typename T>
inline typename BSTree<T>::Node *BSTree<T>::min(Node *tree) const{
    if(NULL == tree)
        return NULL;
    if(NULL == tree->lchild)
        return tree;
    return min(tree->lchild);
}

template<typename T>
bool BSTree<T>::contains(Node *tree,const T &val) const{
    if(NULL == tree) return false;

    if(val < tree->data)
        return contains(tree->lchild,val);
    else if(val > tree->data)
        return contains(tree->rchild,val);
    else
        return true;
}

template<typename T>
void BSTree<T>::clear(Node **tree){
    if(*tree != NULL){
        clear(&(*tree)->lchild);
        clear(&(*tree)->rchild);
        delete *tree;
    }
    *tree = NULL; 
}

template<typename T>
void BSTree<T>::print(Node *tree,std::ostream &out) const{
    if(tree){
        print(tree->lchild,out);
        out<<tree->data<<" ";
        print(tree->rchild,out);
    }
}

template<typename T>
inline typename BSTree<T>::Node *BSTree<T>::clone(Node *tree) const{
    if(!tree)
        return NULL;
    else
        return new Node(tree->data,clone(tree->lchild),clone(tree->rchild));
}
#endif

/*
 * File: BinarySearchTree.hpp
 * User: wqy
 * CreateTime: 2013-02-20 22:00
 * ModifyTime: 2013-02-20 22:11
 */

#include <iostream>
#include <algorithm>
#include <iterator>
#include <ctime>
#include <cstdlib>
#include "BinarySearchTree.hpp"

using namespace std;

int main(){
    BSTree<int> tree1;
    srandom((int)time(0));
    int i;
    for(i = 0;i < 10;++i)
        tree1.insert(rand()%100+1);
    cout<<"\n########## tree1 ##########"<<endl;
    tree1.print();
    cout<<endl;
    cout<<"size = "<<tree1.size()<<" , min = "<<tree1.min()<<" , max = "<<tree1.max()<<endl;
    tree1.insert(55);
    cout<<"After insert(55): ";
    cout<<(tree1.contains(55) ? "tree1 contains 55" : "tree1 does not contains 55")<<endl;
    tree1.clear();
    cout<<"After clear(): ";
    cout<<(tree1.isEmpty() ? "tree1 empty" : "tree1 not empty")<<endl;

    int arr[] = {6,2,8,1,5,3,4};
    const int SIZE = sizeof(arr) / sizeof(arr[0]);
    vector<int> v;
    copy(arr,arr+SIZE,back_inserter(v));
    cout<<"\n########## v ##########"<<endl;
    copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
    cout<<endl;

    BSTree<int> tree2(v);
    cout<<"\n########## tree2 #########"<<endl;
    tree2.print();
    cout<<endl;
    tree2.remove(2);
    cout<<"After remove(2): ";
    tree2.print();
    cout<<endl;

    BSTree<int> tree3;
    tree3 = tree2;
    cout<<"\n########## tree3 #########"<<endl;
    tree3.print();
    cout<<endl;

    BSTree<int> tree4(tree3);
    cout<<"\n########## tree4 #########"<<endl;
    tree4.print();
    cout<<endl;

    return 0;
}

测试结果:

二叉搜索树 - system404 - system404
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值