二叉查找树

二叉查找树是一种有限制规则的二叉树,规定二叉树中所有节点的右子树中的所有项都大于节点的项,左子树中的所有项都小于节点中的项。

所以二叉查找树有利于对数据项进行查找。

二叉查找树中主要涉及的操作有:遍历,查找(查找值为key的节点、查找最小,最大节点、查找比当前节点大的最小节点、查找比当前节点小的最大节点)、插入、删除、销毁、打印)

完整的二叉查找树代码

#ifndef BSTREE_H
#define BSTREE_H
#include<iostream>
#include<iomanip>
using namespace std;
template <typename T>
class BSTNode
{
public:
    T key;
    BSTNode *left;
    BSTNode *right;
    BSTNode *parent;
    BSTNode(T value,BSTNode *p,BSTNode *l,BSTNode *r):key(value)
      ,parent(p),left(l),right(r){}
};
template <typename T>
class BSTree
{
private:
    BSTNode<T> *mRoot;
public:
    BSTree();
    ~BSTree();
    //前序遍历
    void preOrder();
    //中序遍历
    void inOrder();
    //后序遍历
    void postOrder();
    //在二叉树中查找值为key的节点
    BSTNode<T>* search(T key);
    //在二叉树中查找值为key的节点(非递归)
    BSTNode<T>* iterativeSearch(T key);
    //查找最小节点
    T minimum();
    //查找最大节点
    T maximum();
    //查找二叉树中数据值大于该节点的最小节点
    BSTNode<T>* successor(BSTNode<T> *x);
    //查找二叉树中数据值小于该节点的最大节点
    BSTNode<T>* predecessor(BSTNode<T>*x);
    //将节点插入到二叉树中
    void insert(T key);
    //删除节点
    void remove(T key);
    //销毁二叉树
    void destroy();
    //打印二叉树
    void print();
private:
    void preOrder(BSTNode<T>* tree)const;
    void inOrder(BSTNode<T>* tree)const;
    void postOrder(BSTNode<T>* tree)const;
    BSTNode<T>* search(BSTNode<T>*x,T key)const;
    BSTNode<T>* iterativeSearch(BSTNode<T>*x,T key)const;
    BSTNode<T>* minimum(BSTNode<T>* tree);
    BSTNode<T>* maximum(BSTNode<T>* tree);
    void insert(BSTNode<T>* &tree,BSTNode<T> *z);
    BSTNode<T>* remove(BSTNode<T>* &tree,BSTNode<T>*z);
    void destroy(BSTNode<T>* &tree);
    void print(BSTNode<T>*tree,T key,int direction);



};
//构造函数
template <typename T>
BSTree<T>::BSTree():mRoot(nullptr)
{

}
//析构函数
template<typename T>
BSTree<T>::~BSTree()
{
    destroy();
}
template<class T>
void BSTree<T>::preOrder(BSTNode<T>* tree)const
{
    if(tree!=nullptr)
    {
        cout<<tree->key<<" ";
        preOrder(tree->left);
        preOrder(tree->right);
    }
}
template<class T>
void BSTree<T>::preOrder()
{
    preOrder(mRoot);
}

template<class T>
void BSTree<T>::inOrder(BSTNode<T>* tree)const
{
    if(tree!=nullptr)
    {
        inOrder(tree->left);
        cout<<tree->key<<"  ";
        inOrder(tree->right);
    }

}
template<class T>
void BSTree<T>::inOrder()
{
    inOrder(mRoot);
}

template<class T>
void BSTree<T>::postOrder(BSTNode<T>*tree)const
{
    if(tree!=nullptr)
    {
        postOrder(tree->left);
        postOrder(tree->right);
        cout<<tree->key<<"  ";

    }
}
template<class T>
void BSTree<T>::postOrder()
{
    postOrder(mRoot);
}
template<class T>
BSTNode<T>* BSTree<T>::search(BSTNode<T> *x, T key) const
{
    if(x==nullptr||x->key==key)
        return x;
    if(key<x->key)
        return search(x->left,key);
    else
        return search(x->right,key);
}
template<class T>
BSTNode<T>* BSTree<T>::search(T key)
{
    search(mRoot,key);
}
template<class T>
BSTNode<T>* BSTree<T>::iterativeSearch(BSTNode<T> *x, T key) const
{
    while((x!=nullptr)&&(x->key!=key))
    {
        if(key<x->key)
            x=x->left;
        else
            x=x->right;
    }
}
template<class T>
BSTNode<T>* BSTree<T>::minimum(BSTNode<T>*tree)
{
    if(tree==nullptr)
        return nullptr;
    while(tree->left!=nullptr)
    {
        tree=tree->left;
    }
    return tree;
}
template<class T>
T BSTree<T>::minimum()
{
    BSTNode<T>* p=minimum(mRoot);
    if(p!=nullptr)
    {
        return p->key;
    }
    return (T)nullptr;
}
template<class T>
BSTNode<T>* BSTree<T>::maximum(BSTNode<T>* tree)
{
    if(tree==nullptr)
        return nullptr;
    while(tree->right!=nullptr)
    {
        tree=tree->right;
    }
    return tree;
}
template<class T>
T BSTree<T>::maximum()
{
    BSTNode<T>* p=maximum(mRoot);
    if(p!=nullptr)
    {
        return p->key;
    }
    return (T)nullptr;

}
template<class T>
BSTNode<T>* BSTree<T>::successor(BSTNode<T> *x)
{
    if(x->right!=nullptr)
        return minimum(x->right);
    BSTNode<T>* y=x->parent;
    while((y!=nullptr)&&(x==y->right))
    {
        x=y;
        y=y->parent;
    }
    return y;
}
template<class T>
BSTNode<T>* BSTree<T>::predecessor(BSTNode<T> *x)
{
    if(x->left!=nullptr)
        return maximum(x->left);
    BSTNode<T>* y=x->parent;
    while((y!=nullptr)&&(x==y->left))
    {
        x=y;
        y=y->parent;
    }
    return y;
}
template<class T>
void BSTree<T>::insert(BSTNode<T> *&tree, BSTNode<T> *z)
{
    BSTNode<T>*y=nullptr;
    BSTNode<T>*x=tree;
    while(x!=nullptr)
    {
        y=x;
        if(z->key<x->key)
            x=x->left;
        else
            x=x->right;

    }
    z->parent=y;
    if(y==nullptr)
        tree=z;
    else if(z->key<y->key)
           y->left=z;
    else
        y->right=z;


}
template<class T>
void BSTree<T>::insert(T key)
{
    BSTNode<T>* z=nullptr;
    if((z=new BSTNode<T>(key,nullptr,nullptr,nullptr))==nullptr)
        return;
    insert(mRoot,z);
}
template<class T>
BSTNode<T>* BSTree<T>::remove(BSTNode<T> *&tree, BSTNode<T> *z)
{
    BSTNode<T>*x=nullptr;
    BSTNode<T>*y=nullptr;
    if((z->left==nullptr)||(z->right==nullptr))
        y=z;
    else
        y=successor(z);
    if(y->left!=nullptr)
        x=y->left;
    else
        x=y->right;
    if(x!=nullptr)
        x->parent=y->parent;
    if(y->parent==nullptr)
        tree=x;
    else if(y==y->parent->left)
        y->parent->right=x;
    else
        y->parent->right=x;
    if(y!=z)
        z->key=y->key;
    return y;
}
template<class T>
void BSTree<T>::remove(T key)
{
    BSTNode<T>*z,*node;
    if((z=search(mRoot,key))!=nullptr)
    {
        if((node=remove(mRoot,z))!=nullptr)
            delete node;
    }
}
template<class T>
void BSTree<T>::print(BSTNode<T>* tree,T key,int direction)
{
    if(tree!=nullptr)
    {
        if(direction==0)
            cout<<setw(2)<<tree->key<<"is root"<<endl;
        else
            cout<<setw(2)<<tree->key<<"is "<<setw(2)<<key<<"’s"<<setw(12)<<(direction==1?"right child":"left child")<<endl;
        print(tree->left,tree->key,-1);
        print(tree->right,tree->key,1);

    }
}
template <class T>
void BSTree<T>::print()
{
    if(mRoot!=nullptr)
        print(mRoot,mRoot->key,0);
}
template<class T>
void BSTree<T>::destroy(BSTNode<T>* &tree)
{
    if(tree==nullptr)
        return;
    if(tree->left!=nullptr)
        return destroy(tree->left);
    if(tree->right!=nullptr)
        return destroy(tree->right);
    delete tree;
    tree=nullptr;
}
template<class T>
void BSTree<T>::destroy()
{
    destroy(mRoot);
}

#endif // BSTREE_H

代码解析

三种遍历方法
采用递归方法对树进行遍历

//前序遍历
template<class T>
void BSTree<T>::preOrder(BSTNode<T>*tree)const
{
if(tree!=nullptr)
{
cout<<tree->key<<" ";
preOrder(tree->left);
preOrder(tree->right);
}
//中序遍历
template<class T>
void BSTree<T>::inOrder(BSTNode<T>*tree)const
{
if(tree!=nullptr)
{
inOrder(tree->left);
cout<<tree->key<<" ";
inOrder(tree->right);
}
//后序遍历
template<class T>
void BSTree<T>::postOrder(BSTNode<T>*tree)const
{
if(tree!=nullptr)
{
postOrder(tree->left);
postOrder(tree->right);
cout<<tree->key<<" ";
}

查找

1 查找值为key的节点
先查找根节点,如果小于根节点就查找左子树,如果大于根节点就查找右子树。

template<class T>
BSTNode<T>*BSTree<T>::search(BSTNode<T>*x,T key)const
{
if(x==nullptr||x->key==key)
return x;
if(key<x->key)
return search(x->left,key);
else
return seach(x->right,key);
}

2 查找二叉树最小节点
二叉树最小节点就是沿着左子树查找的最后的一个节点

template<class T>
BSTNode<T>*BSTree<T>::minimum(BSTNode<T>*tree)
{
if(tree==nullptr)
return nullptr;
while(tree->left!=nullptr)
{
tree=tree->left;
}
return tree;
}

3 查找二叉树最大节点
查找最大节点,查找二叉树右子树的最后一个节点

template<class T>
BSTNode<T>*BSTree<T>::maximum(BSTNode<T>*tree)
{
if(tree==nullptr)
return nullptr;
while(tree->right!=nullptr)
{
tree=tree->right;
}
return tree;
}

4 查找当前节点的前驱节点
当前节点的前驱节点就是比这个节点的值小的节点,如果这个节点有左子树,就是查找这个节点的左子树的最大节点,如果没有左子树,那么如果这个节点是他的父节点的右节点,那么他的父节点就是他的前驱节点,如果这个节点是父节点的左节点,那么就查找它父节点的父节点。

template<class T>
BSTNode<T>*BSTree<T>::predecessor(BSTNode<T>*x)
{
if(x->left!=nullptr)
return maximum(x->left);
BSTNode<T>*y=x->parent;
while((y!=nullptr)&&(x==y->left))
{
x=y;
y=y->parent;
}
return y;
}

5 查找当前节点的后继节点
如果当前节点有右子树,那么他的后继节点就是右子树的最小值,如果没有右子树,那么如果当前节点是父节点的左子树,那么他的后继节点是他的父节点,如果当前节点是父节点的右子树,那么他的后继节点是直到他的父节点作为父节点的父节点的左子树为止。

template<class T>
BSTNode<T>*BSTree<T>::successor(BSTNode<T>*tree)const
{
if(tree->right!=nullptr)
return minimum(x->right);
BSTNode<T>*y=x->parent;
while((y!=nullptr)&&(x==y->right))
{
x=y;
y=y->parent;
}
return y;
}

6 插入
插入算法就是如果插入的节点的值大于当前节点,那么就插入到右子树中,如果小于当前节点,那么就插入到左子树中。插入可以采用递归算法和非递归算法

//递归算法
template<class T>
void BSTree<T>::insert(BSTNode<T>*&tree,BSTNode<T>*z)
{
if(tree==nullptr)
tree=z;
else if(z->key<tree->key)
insert(tree->left,z)
else if(z->key>tree->key)
insert(tree->right,z);
}
//非递归算法
template<class T>
void BSTree<T>::insert(BSTNode<T>*&tree,BSTNode<T>*z)
{
BSTNode<T>*y=nullptr;
BSTNode<T>*x=tree;
while(x!=nullptr)
{
y=x;
if(z->key<x->key)
x=x->left;
else
x=x->right;
}
if(y==nullptr)
tree=z;
else if(z->key<y->key)
y->left=z;
else
y->right=z;

7 删除
从二叉树中删除一个节点分好几种情况,如果要删除的节点只有一个儿子,那么将节点删除,直接将这个节点的父节点作为儿子节点的父节点。如果节点有两个儿子,那么查找这个节点的后继节点,

template<class T>
BSTNode<T>* BSTree<T>::remove(BSTNode<T>*&tree,BSTNode<T>*z)
{
BSTNode<T>*x=nullptr;
BSTNode<T>*y=nullptr;
if((z->left==nullptr)||(z->right==nullptr))
y=z;
else
y=successor(z);
if(y->left!=nullptr)
x=y->left;
else
x=y->right;
if(x!=nullptr)
x->parent=y->parent;
if(y->parent==nullptr)
tree=x;
else if(y==y->parent->left)
y->parent->right=x;
if(y!=z)
z->key=y->key;
return y;
}

8 打印
打印二叉树相当于遍历,可以采用前序、后序、中序。

//direction等于0表示该节点是跟节点,direction等于-1表示该节点是它父节点的左孩子,direction等于1表示该节点是它父节点的右孩子。
template<class T>
void BSTree<T>::print(BSTNode<T>*tree,T key,int direction)
{
if(tree!=nullptr)
{
if(direction==0)
cout<<tree->key<<"is root"<<endl;
else
cout<<tree->key<<is<<key<<"'s"<<(direction==1?"right child":"left child")<<endl;
print(tree->left,tree->key,-1);
print(tree->right,tree->key,1);
}

}

9 销毁
采用递归方法

template<class T>
void BSTree<T>::destroy(BSTNode<T>*&tree)
{
if(tree==nullptr)
return;
if(tree->left!=nullptr)
return destroy(tree->left);
if(tree->right!=nullptr)
return destroy(tree->right);
delete tree;
tree=nullptr;
}

二叉查找树的所有节点的平均深度为O(logN)但是二叉查找树在经过不断的插入和删除操作会达到二叉树出现不平衡的状态,为了使树在插入和删除过程中达到平衡状态需要添加平衡条件,AVL树就是一种经典的平衡查找树。还有一种方法是通过自调整使树达到和平衡一样的效果,这种数据结构叫做伸展树。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值