数据结构:二叉搜索树

来源:互联网 发布:js将list转换为数组 编辑:程序博客网 时间:2024/05/18 21:42

资料摘自<数据结构C++语言描述>

一棵普通的二叉树中可以存放数据,且在我们需要增加、删除或查找数据项时能提供快速访问。树结构可以显著地发送搜索的性能,因为到达一个数据的路径最长不超过树的深度。

       对于一个含10000个元素的表,用顺序搜索法查找一个元素的预期比较次数是5000,而在一棵完全二叉树上进行同样的搜索,需要进行的比较不会超过14次。


为了将元素存储在树中以供有效访问,必须设计一种可以标识到达元素的路径的搜索结构。这种结构被称作二叉搜索树,它用关系运算符<对元素进行排序。为了比较树中的结点,我们可以将数据域的整体或部分指定为键值,每当树中添加一项,“<”运算符都要将其与键值比较。二叉搜索树由下列规则构成:

       对于每个节点,其左子树中的数据值都小于节点本身的值,而右子树中的数据值都大于或等于节点值。

下面图11.14是一个二叉搜索树的一个例子:


搜索37,由根开始需要4次比较:

当前节点        动作

根=50           比较键值37和50,因为37<50,故扫描左子树

节点=30        比较键值37和30,因为37>30,故扫描右子树

节点=35        比较键值37和35,因为37>35,故扫描右子树

节点=37        比较键值37和37,找到数据项

下面是二叉搜索树的部分定义与实现:

template<class T>
class BinSTree
{
protected:
    TreeNode<T> * root;
    TreeNode<T> * current;
    int size;
    TreeNode<T> * getTreeNode(const T & item, TreeNode<T> *lptr, TreeNode<T> * rptr); //
    void freeTreeNode(TreeNode<T> * p); //
    TreeNode<T> * copyTree(TreeNode<T> * t); //
    void deleteTree(TreeNode<T> * t); //
    TreeNode<T> * findNode(const T & item, TreeNode<T> * & parent) const; //
public:
    BinSTree();
    BinSTree(const BinSTree<T> & tree);
    ~BinSTree();
    BinSTree<T> & operator = (const BinSTree<T> & rhs);  //
    bool find(T & item); //
    void insert(const T & item); //
    void Delete(const T & item); //
    void clearTree(); // ==
    bool listEmpty() const; //
    int listSize() const; //
    void update(const T & item); //
    TreeNode<T> * getRoot() const; //
};

template<class T>
TreeNode<T> * BinSTree<T>::getTreeNode(const T& item, TreeNode<T> *lptr, TreeNode<T> *rptr){
    TreeNode<T> * p;
    p = new TreeNode<T>(item,lptr,rptr);
    if(p == NULL){
        std::cerr<<"memory allocation failure ! "<<std::endl;
        exit(1);
    }
    return p;
}

template<class T>
void BinSTree<T>::freeTreeNode(TreeNode<T> * p){
    delete p;
}

template<class T>
TreeNode<T> * BinSTree<T>::copyTree(TreeNode<T> * t){
    TreeNode<T> *newlptr, *newrptr, *newnode;
    if(t == NULL){
        return NULL;
    }
    if(t->Left() != NULL){
        newlptr = copyTree(t->Left());
    }else{
        newlptr = NULL;
    }
    if(t->Right() != NULL){
        newrptr = copyTree(t->Left());
    }else{
        newrptr = NULL;
    }
    newnode = getTreeNode(t->data, newlptr, newrptr);
    return newnode;
}

template<class T>
void BinSTree<T>::deleteTree(TreeNode<T> * t){
    if(t != NULL){
        deleteTree(t->Left());
        deleteTree(t->Right());
        freeTreeNode(t);
    }
}

template<class T>
int BinSTree<T>::listSize() const{
    return this->size;
}

template<class T>
bool BinSTree<T>::listEmpty() const {
    return this->size == 0;
}

template<class T>
TreeNode<T> * BinSTree<T>::getRoot() const{
    return this->root;
}

template<class T>
BinSTree<T> & BinSTree<T>::operator=(const BinSTree<T> & rhs){
    if(this == rhs){
        return *this;
    }
    this->clearList();
    this->root = this->copyTree(rhs.root);
    this->current = this->root;
    this->size = rhs.size;
    return * this;
}

template<class T>
TreeNode<T> * BinSTree<T>::findNode(const T & item, TreeNode<T> * & parent) const {
    TreeNode<T> * t = this->root;
    parent = NULL;
    while(t !== NULL){
        if(item == t->data){
            break;
        }else{
            parent = t;
            if(item < t->data){
                t = t->Left();
            }else{
                t = t->Right();
            }
        }
    }
    return t;
}

template<class T>
bool BinSTree<T>::find(T & item) {
    TreeNode<T> * parent;
    this->current = this->findNode(item, parent);
    if(this->current != NULL){
        //item = this->current->data;
        return true;
    }else{
        return false;
    }
}

//insert方法以新数据项为参数对树进行搜索以找到合适的位置将其添加
//到树中。函数反复扫描左右子树中的路径直到找到插入点的位置。对于
//对于路径中的每一步,算法才都记录下当前节点(称作t)以及当前节点的
//双亲(称作parent)。整个过程在我们识别出空子树(t=NULL)后终止,它
//表示我们已经找到插入新数据项的位置。此时将新节点作为双亲的子节
//点插入到该位置。
template<class T>
void BinSTree<T>::insert(const T & item){
    TreeNode<T> * t = this->root, * parent = NULL, *newNode;
    while(t != NULL){
        parent = t;
        if(item < t->data){
            t = t->Left();
        }else{
            t = t->Right();
        }
    }
    newNode = this->getTreeNode(item,NULL,NULL);
    if(parent == NULL){
        this->root = newNode;
    }else if(item < parent->data){
        parent->left = newNode;
    }else{
        parent->right = newNode;
    }
    ++this->size;
}

//若item在树中,将其删除
template<class T>
void BinSTree<T>::Delete(const T & item){
    //DNodePtr 指向被删除节点D
    //PNodePtr 指向节点D的双亲节点
    //RNodePtr 指向替换D节点
    TreeNode<T> * DNodePtr, * PNodePtr, * RNodePtr;
    //搜索数据值为item的节点,并保存该节点的双亲节点指针
    if((DNodePtr = this->findNode(item,PNodePtr)) == NULL) {
        return;
    }
    //若D有一个指针为NULL,则替换节点为其另一枝的某一节点
    if(DNodePtr->Right() == NULL){
        RNodePtr = DNodePtr->Left();
    }else if(DNodePtr->Left() == NULL){
        RNodePtr = DNodePtr->Right();
    }else{
        //DNodePtr的两个子节点均不为NULL
        //寻找并卸下D的替换节点。
        //从节点D的左子树开始,找数据值小于D的数据值的
        //最大值,将该节点从树中断开
        //PofRNodePtr 指向替换节点双亲的指针
        TreeNode<T> * PofRNode = DNodePtr;
        //第一种可能的替换为D的左节点
        RNodePtr = DNodePtr->left;
        //从D的左节点的右子树继续往下搜索最大值,并记录当前节点及其双亲节点
        //指针,最后我们找到替换节点
        while(RNodePtr->right != NULL){
            PofRNode = RNodePtr;
            RNodePtr = RNodePtr->right;
        }
        if(PofRNode == DNodePtr){
            //被删除节点的左节点为替换节点,将D的右子树赋给R
            RNodePtr->right = DNodePtr->right;
        }else{
            //至少往右子树移动了一个节点,从树中删除替换节点,将其左子树赋给其双亲
            PofRNode->right = RNodePtr->left;
            //用替换节点代替DNodePtr
            RNodePtr->left = DNodePtr->left;
            RNodePtr->right = DNodePtr->right;
        }
    }
    //完成到双亲节点的连结
    if(PNodePtr == NULL){
        this->root = RNodePtr;
    }else if(DNodePtr->data < PNodePtr->data){
        //要删除的节点位于左子树上
        PNodePtr->left = RNodePtr;
    }else{
        PNodePtr->right = RNodePtr;
    }
    this->freeTreeNode(DNodePtr);
    --this->size;
}

//更新节点数据
template<class T>
void BinSTree<T>::update(const T & item){
    if(this->current != NULL && this->current->data == item){
        this->current->data = item;
    }else{
        insert(item);
    }
}



0 0
原创粉丝点击