定义


二叉搜索树(Binary Search Tree)或称二叉查找树,也称二叉排序树(Binary Sort Tree)。它或者是一棵空树,或者是具有下列性质的二叉树:


若左子树不空,则左子树上所有节点的值均小于它的根节点的值;

若右子树不空,则右子树上所有节点的值均大于它的根节点的值;

左、右子树也分别为二叉搜索树;

性质


二叉搜索树与普通二叉树相比,有一些优秀的特征或性质:


由于节点是有序排放的:左子树<根节点<右子树。故在查找一个节点的时候,只需先和根节点比较,再决定是进入左子树还是右子树查找。而普通二叉树需要一个一个地遍历。

查找、插入的时间复杂度是O(h),h是树的高度。即当树的高度尽量低(比较平衡)时,效率高。

算法解释


不得不说,非线性结构的操作确实难于线性结构的,有些算法的逻辑比较复杂。下面对代码中给出的部分算法进行解释,便于阅读。


构造方法:BinarySearchTree();建树的过程就是一个插入的过程,所以插入操作是重要的。

求叶子节点数:int leaf();按某种方式遍历树,若左右孩子皆为空,即为叶子节点。代码中是按中序遍历的。

查找指定节点:bool search(ElemType);根据二叉搜索树节点的分布特点,查找只需在左或右子树中进行,并且插入树中已有的节点也算插入失败。插入操作逻辑比较清楚,代码易看懂。

获取指定节点的前驱:BTNode* predecessor(ElemType);这个操作在普通二叉树中是没有的。在二叉搜索树中,某节点的前驱指的是中序遍历时的前驱。故该操作本质上是一个中序遍历的过程。稍微不同的是,在遍历的过程中需要记录最近一次遍历的节点plastVisit,并判断当前访问的节点是否是指定节点。若是,则返回plastVisit。

获取后继和获取前驱的道理是一样的。

获取最小节点:BTNode* minimum();二叉搜索树中的最小节点一定是位于左子树(如果存在)。于是,不断遍历左子树即可,比较简单。

获取最大节点:BTNode* maximum();二叉搜索树中的最大节点一定是位于右子树(如果存在)。于是,不断遍历右子树即可,比较简单。

插入节点:bool insertNode(ElemType);插入的过程本质上也是查找,需要记住的是:新节点会插入到叶子节点处。

遍历:void traverse();二叉搜索树的遍历可以是多样的,各种遍历方式也在上一篇二叉树中实现了,这里只给出中序遍历。因为,对一棵二叉搜索树进行中序遍历会得到节点从小到大的排序序列。

删除节点:bool deleteNode(ElemType);删除的规则是这样的:

若待删节点无左子树,则用其右子树的根节点替换它。

若待删节点有左子树,则在左子树中寻找中序遍历的最后一个节点,用该节点替换它。

删除规则比较好看懂,但具体实施时,细节繁多,很不容易。这也是所有操作中最复杂的。画图理解:


二叉搜索树_二叉搜索树


其它操作在上一篇二叉树中已有所解释,不再赘述。具体细节还得看代码,代码较长,建议以方法为单位来理解,

代码

类定义


#include<iostream>  
#include<iomanip>  
#include<stack>  
#include<queue>  
using namespace std;  
typedef int ElemType;  
//二叉树节点  
class BTNode   //Binary Tree Node  
{  
public:  
    ElemType data;  
//左孩子  
//右孩子  
    BTNode(ElemType d, BTNode* left = NULL, BTNode* right = NULL)  
        :data(d), lchild(left), rchild(right){}  
};  
//二叉搜索树  
class BinarySearchTree  
{  
private:  
//树根  
    BTNode* Root;  
//节点总数  
int size;  
public:  
//构造方法  
    BinarySearchTree();  
//析构方法  
    ~BinarySearchTree();  
//判断树空  
bool empty()  
return Root == NULL;}  
//求节点总数  
int getSize()  
return size;}  
//求叶子节点数  
int leaf();  
//查找  
bool search(ElemType);  
//获取父节点  
    BTNode* parent(ElemType);  
//获取前驱  
    BTNode* predecessor(ElemType);  
//获取后继  
    BTNode* successor(ElemType);  
//获取最小节点  
    BTNode* minimum();  
//获取最大节点  
    BTNode* maximum();  
//插入新节点  
bool insertNode(ElemType);  
//删除节点  
bool deleteNode(ElemType);  
//中序遍历  
void traverse()  
    {inOrderWithoutRecursion();}  
void inOrderWithoutRecursion();  
};



类实现


//构造方法  
BinarySearchTree::BinarySearchTree()  
{  
    size = 0;  
    Root = NULL;  
    ElemType data;  
"建树,输入节点,输入0结束:";  
while (cin >> data && data)  
        insertNode(data);  
}  
//析构方法  
BinarySearchTree::~BinarySearchTree()  
{  
if (!empty())  
    {  
        queue<BTNode*> q;  
        q.push(Root);  
        BTNode* p = NULL;  
while (!q.empty())  
        {  
            p = q.front();  
            q.pop();  
//左孩子不为空,则左孩子入队  
if (p->lchild)  
                q.push(p->lchild);  
//右孩子不为空,则右孩子入队  
if (p->rchild)  
                q.push(p->rchild);  
//释放内存  
delete p;  
        }  
    }  
}  
//求叶子节点数  
int BinarySearchTree::leaf()  
{  
int num = 0;  
//按中序遍历  
if (!empty())  
    {  
        stack<BTNode*> s;  
        BTNode* p = Root;  
while (!s.empty() || p)  
        {  
if (p)  
            {  
                s.push(p);  
                p = p->lchild;  
            }  
else  
            {  
                p = s.top();  
                s.pop();  
//左右子树均为空,则为叶子节点  
if (p->lchild == NULL && p->rchild == NULL)  
                    num++;  
                p = p->rchild;  
            }  
        }  
    }  
return num;  
}  
//查找  
bool BinarySearchTree::search(ElemType data)  
{  
if (!empty())  
    {  
        BTNode* p = Root;  
while (p)  
        {  
if (data == p->data)  
return true;  
else if (data < p->data)  
                p = p->lchild;  
else  
                p = p->rchild;  
        }  
    }  
//树空或查找失败  
return false;  
}  
BTNode* BinarySearchTree::parent(ElemType data)  
{  
if (!empty())  
    {  
//根节点的父节点为空  
if (Root->data == data)  
return NULL;  
        stack<BTNode*> s;  
        BTNode* p = Root;  
while (!s.empty() || p)  
        {  
if (p)  
            {  
                s.push(p);  
                p = p->lchild;  
            }  
else  
//左子树访问完后,访问右子树  
                p = s.top();  
                s.pop();  
if ((p->lchild && p->lchild->data == data) || (p->rchild && p->rchild->data == data))  
return p;  
                p = p->rchild;  
            }  
        }  
    }  
return NULL;  
}  
//获取前驱  
BTNode* BinarySearchTree::predecessor(ElemType data)  
{  
    BTNode* pcur, *plastVisit;  
    pcur = plastVisit = NULL;  
if (!empty())  
    {  
        stack<BTNode*> s;  
        pcur = Root;  
while (!s.empty() || pcur)  
        {  
if (pcur)  
            {  
//plastVisit = pcur;  
                s.push(pcur);  
                pcur = pcur->lchild;  
            }  
else  
            {  
                pcur = s.top();  
                s.pop();  
if (pcur->data == data)  
return plastVisit;  
else  
                    plastVisit = pcur;  
                pcur = pcur->rchild;  
            }  
        }  
    }  
return plastVisit;  
}  
//获取后继  
BTNode* BinarySearchTree::successor(ElemType data)  
{  
    BTNode* pcur = NULL;  
    pcur = Root;  
if (!empty())  
    {  
        stack<BTNode*> s;  
while (!s.empty() || pcur)  
        {  
if (pcur)  
            {  
                s.push(pcur);  
                pcur = pcur->lchild;  
            }  
else  
            {  
                pcur = s.top();  
                s.pop();  
if (pcur->data == data)  
return pcur->rchild;  
                pcur = pcur->rchild;  
            }  
        }  
    }  
//空树  
return NULL;  
}  
//获取最小节点  
BTNode* BinarySearchTree::minimum()  
{  
//最小节点在左子树最下边  
if (!empty())  
    {  
        BTNode* p = Root;  
while (p->lchild)  
            p = p->lchild;  
return p;  
    }  
//树空  
return NULL;  
}  
//获取最大节点  
BTNode* BinarySearchTree::maximum()  
{  
//最大节点在右子树最下边  
if (!empty())  
    {  
        BTNode* p = Root;  
while (p->rchild)  
            p = p->rchild;  
return p;  
    }  
//树空  
return NULL;  
}  
//插入新节点  
bool BinarySearchTree::insertNode(ElemType data)  
{  
/*
     新节点都会被插入到叶子处
     插入一般不会失败,除非是插入了重复节点。
    */  
if (Root == NULL)  
    {  
new BTNode(data);  
        size++;  
return true;  
    }  
else  
    {  
        BTNode* p = Root;  
while (true)  
        {  
if (data < p->data)  
            {  
//如果有左子树,则继续遍历左子树  
if (p->lchild)  
                    p = p->lchild;  
else  
//否则,插入节点,下同  
new BTNode(data);  
break;  
                }  
            }  
else if (data > p->data)  
            {  
if (p->rchild)  
                    p = p->rchild;  
else  
                {  
new BTNode(data);  
break;  
                }  
            }  
else//遇到重复节点  
return false;  
        }  
//插入新节点成功,节点总数加一  
        size++;  
return true;  
    }  
}  
//删除节点  
bool BinarySearchTree::deleteNode(ElemType data)  
{  
/*
    删除规则
    1.若待删节点无左子树,则用其右子树的根节点替换它。
    2.若待删节点有左子树,则在左子树中寻找中序遍历的最后一个节点,用该节点替换它。
    */  
if (!empty())  
    {  
//树中无此节点,删除失败  
if (!search(data))  
return false;  
/*
        p:待删结点
        Parent:待删除节点的父节点
        temp:替换节点
        tempp:替换节点的父节点
        */  
        BTNode* p, *Parent, *temp, *tempp;  
        p = Parent = temp = tempp = NULL;  
//获取待删除节点的父节点  
        Parent = parent(data);  
//根据父节点,确定待删结点  
if (Parent->lchild && Parent->lchild->data == data)  
            p = Parent->lchild;  
else  
            p = Parent->rchild;  
//如果左子树不为空,查找其中序遍历的最后一个节点  
if (p->lchild)  
        {  
            temp = p->lchild;  
while (temp->rchild)  
            {  
                tempp = temp;  
//不断遍历右子树  
                temp = temp->rchild;  
            }  
//如果p的左孩子即是替换节点  
if (tempp == NULL)  
                p->lchild = temp->lchild;  
else//替换节点的左子树作为其父节点的右子树(这句难以理解,需要多想想)  
                tempp->rchild = temp->lchild;  
//替换节点继承待删结点的左右孩子  
            temp->lchild = p->lchild;  
            temp->rchild = p->rchild;  
        }  
else  
            temp = p->rchild;  
//替换节点替换掉待删结点(这也是为什么需要找到待删结点的父节点)  
if (Parent == NULL)  //待删结点恰为根节点  
            Root = temp;  
else if (Parent->lchild == p)  //待删结点本身处于左子树  
            Parent->lchild = temp;  
else//待删结点本身处于右子树  
            Parent->rchild = temp;  
//删除待删结点  
delete p;  
//节点总数减一  
        size--;  
return true;  
    }  
//树空  
return false;  
}  
//中序遍历  
void BinarySearchTree::inOrderWithoutRecursion()  
{  
if (!empty())  
    {  
        stack<BTNode*> s;  
        BTNode* p = Root;  
while (!s.empty() || p)  
        {  
if (p)  
            {  
                s.push(p);  
                p = p->lchild;  
            }  
else  
            {  
                p = s.top();  
                s.pop();  
                cout << setw(4) << p->data;  
                p = p->rchild;  
            }  
        }  
        cout << endl;  
    }  
}



主函数



int main()  
{  
"******二叉搜索树***by David***" << endl;  
    BinarySearchTree tree;  
"中序遍历" << endl;  
    tree.traverse();  
"树中节点总数 " << tree.getSize() << endl;  
"叶子节点数 " << tree.leaf() << endl;  
    BTNode* p = NULL;  
    p = tree.minimum();  
"最小节点是 " << p->data << endl : cout << "树空!" << endl;  
    p = tree.maximum();  
"最大节点是 " << p->data << endl : cout << "树空!" << endl;  
    ElemType data = 2;  
"查找节点 " << data << endl;  
if (tree.search(data))  
    {  
"节点 " << data << " 查找成功!" << endl;  
        p = tree.predecessor(data);  
"节点 " << data << " 的前驱是 " << p->data << endl : cout << "无前驱!" << endl;  
        p = tree.successor(data);  
"节点 " << data << " 的后继是 " << p->data << endl : cout << "无后继!" << endl;  
    }  
else  
"节点 " << data << "不在树中!" << endl;  
    data = 6;  
"删除节点 " << data << endl;  
if (tree.deleteNode(data))  
    {  
"删除成功!" << endl;  
"中序遍历" << endl;  
        tree.traverse();  
"树中节点总数 " << tree.getSize() << endl;  
"叶子节点数 " << tree.leaf() << endl;  
        data = 5;  
"查找节点 " << data << endl;  
if (tree.search(data))  
        {  
"节点 " << data << " 查找成功!" << endl;  
            p = tree.predecessor(data);  
"节点 " << data << " 的前驱是 " << p->data << endl : cout << "无前驱!" << endl;  
            p = tree.successor(data);  
"节点 " << data << " 的后继是 " << p->data << endl : cout << "无后继!" << endl;  
        }  
else  
"节点 " << data << "不在树中!" << endl;  
    }  
else  
"删除失败!" << endl;  
    cout << endl;  
"pause");  
return 0;  
}


运行


二叉搜索树_二叉搜索树_02

二叉搜索树_中序遍历_03




算法优化


插入算法的一个优化版本



//插入新节点  
bool BinarySearchTree::insertNode(ElemType data)  
{  
    BTNode *parent, *child;  
    parent = NULL;  
    child = Root;  
while (child)  
    {  
        parent = child;  
if (data < child->data)  
            child = child->lchild;  
else if (data > child->data)  
            child = child->rchild;  
else//插入相同关键字的节点,返回false  
return false;  
    }  
//此时parent要么为空,要么就是叶子节点  
if (parent == NULL)//空树  
new BTNode(data);  
else if (data < parent->data)  
new BTNode(data);  
else  
new BTNode(data);  
    size++;  
return true;  
}