【树】二叉搜索树

二叉搜索树

二叉搜索树,也可以叫它二叉查找树二叉排序树。它是一种特殊的二叉树,基本的操作与二叉树并无不同。但是二叉搜索树的特点就是左子树中结点的键值都小于根结点的键值,右子树的键值都大于根结点的键值,简单来说就是左小右大,而且每个结点的键值都不相同,这样在操作的时候就会方便很多。二叉搜索树的操作集比之前的二叉树增加了几个,这样二叉搜索树的操作集就是:创建一个二叉树,判断树空,遍历,查找某个元素查找最值插入删除

具体实现

二叉搜索树
二叉搜索树的存储方式也是链表。先给出头文件和定义,以便之后的局部代码分析。数据类型以int为例,其余同理。空结点的值置为0,应用的时候看具体情况,要把空结点的值置为在树中不可能出现的值,不然可能会出现错误。

#include<iostream>
#include<queue>
#define EMPTYNODE 0//空结点的值为0
using namespace std;

struct node
{
    int data;
    struct node* left;
    struct node* right;
};
typedef struct node* N;
创建一个二叉搜索树

与创建一个二叉树一样,采用层序法,就是逐层输入数据,生成二叉搜索树。一定要注意二叉搜索树序列数据输入的顺序,既有二叉搜索树左小右大的顺序,又有一层一层,从左到右的顺序。

N CreateBinTree()//创建一个二叉树
{
    N roof,t;
    int temp;
    cout<<"请输入搜索二叉树序列:";
    cin>>temp;
    if(temp==EMPTYNODE)
    {
        cout<<"该树为空。"<<endl;
        return NULL;
    }
    roof=new node;
    roof->data=temp;
    roof->left=NULL;
    roof->right=NULL;
    queue<N> q;
    q.push(roof);
    while(!q.empty())
    {
        t=q.front();
        q.pop();
        cin>>temp;//输入左孩子
        if(temp!=EMPTYNODE)
        {
            t->left=new node;
            t->left->data=temp;
            t->left->left=NULL;
            t->left->right=NULL;
            q.push(t->left);
        }
        cin>>temp;//输入右孩子
        if(temp!=EMPTYNODE)
        {
            t->right=new node;
            t->right->data=temp;
            t->right->left=NULL;
            t->right->right=NULL;
            q.push(t->right);
        }
    }
    return roof;
}
遍历(层序遍历)

遍历方法也和二叉树是一样的。

void StoryBrowse(N n)//层序遍历
{
    if(!n)
        return ;
    else
    {
        queue<N> q;
        q.push(n);
        while(!q.empty())
        {
            N temp;
            temp=q.front();
            q.pop();
            cout<<temp->data<<" ";
            if(temp->left)
                q.push(temp->left);
            if(temp->right)
                q.push(temp->right);
        }
    }
}
查找某个元素
递归法查找某个元素
N FindX(N n,int x)//递归查找某个元素
{
    if(!n)
    {
        cout<<"该树不含"<<x<<"这个元素。"<<endl;
        return NULL;
    }
    else
    {
        if(n->data==x)
            return n;
        else if(x<n->data)
            return FindX(n->left,x);
        else
            return FindX(n->right,x);
    }
}
非递归法查找某个元素
N Findx(N n,int x)//非递归查找某个元素
{
    if(!n)
    {
        cout<<"该树不含"<<x<<"这个元素。"<<endl;
        return NULL;
    }
    else
    {
        while(n)
        {
            if(n->data==x)
                return n;
            else if(x<n->data)
                n=n->left;
            else
                n=n->right;
        }
        cout<<"该树不含"<<x<<"这个元素。"<<endl;
        return n;//返回为空
    }
}
查找最值

因为二叉搜索树的有序性,所以最值结点一定是叶子结点。最小值结点就是从根结点开始一直向左,直至叶子结点,这个结点就是最小值结点。最大值结点同理,就是一路向右。查找最值可以用递归迭代两种方法实现。

递归法查找最大值
N FindMax(N n)//递归法查找最大值
{
    if(!n)
    {
        cout<<"该树没有最大值。"<<endl;
        return NULL;
    }
    else if(!n->right)//已经到达叶子结点
        return n;
    else//查找右子树
        return FindMax(n->right);
}
迭代法查找最小值
N FindMin(N n)//迭代法查找最小值
{
    if(!n)
    {
        cout<<"该树没有最小值。"<<endl;
        return NULL;
    }
    while(n)
    {
        if(!n->left)//已经到达叶子结点
            return n;
        else
            n=n->left;
    }
}
插入

插入要根据插入元素与当前结点数据的大小关系,如果插入元素<当前结点的数据,那么把这个元素插入到当前结点的左子树上;如果插入元素>当前结点的数据,那么把这个元素插入到当前结点的右子树上;如果插入元素=当前结点的数据,说明这个元素已经存在,不需要再插入了,因为二叉搜索树每个结点的键值都是不同的。

N Insert(N n,int x)//插入一个元素
{
    if(!n)//创建一个只有一个结点的二叉树
    {
        n=new node;
        n->data=x;
        n->left=NULL;
        n->right=NULL;
    }
    else
    {
        if(x<n->data)
            n->left=Insert(n->left,x);
        else if(x>n->data)
            n->right=Insert(n->right,x);
    }
    return n;
}
删除

删除一个结点分为三种情况,第一个是这个结点没有子结点,也就是这个结点就是叶子结点,这种情况最简单了,直接删除就可以;第二个是这个结点只有一个子结点,这种也比较简单,就是让指向这个结点的指针指向这个结点的子结点就可以了;第三个也是最复杂的一种情况,就是这个结点有左右两个子结点,有两种方法,一个是以左子树的最大结点来代替当前结点,另一个是以右子树的最小结点来代替当前结点,这两种方法都是首先进行数据修改,然后再删除最值结点即可。在删除的时候会遇到前两种情况中的一种,也就是说最值结点只可能没有子结点或者只有一个子结点,倘若最值结点有两个子结点(以最大值为例),根据二叉搜索树的性质,最值结点的右孩子要比最值结点大,那么最值结点就不是最大的了,所以不可能出现这种情况。

以左子树最大结点代替当前结点
N DeleteX(N n,int x)//删除某个元素(以左子树最大结点代替当前结点)
{
    if(!n)
    {
        cout<<"树中没有该元素,无法进行删除操作。"<<endl;
        return NULL;
    }
    else
    {
        if(x<n->data)
            n->left=DeleteX(n->left,x);
        else if(x>n->data)
            n->right=DeleteX(n->right,x);
        else//要删除的是当前结点
        {
            N temp;
            if(n->left&&n->right)//有左右两棵子树
            {
                temp=FindMax(n->left);
                n->data=temp->data;
                n->left=DeleteX(n->left,n->data);
            }
            else //只有一个子结点或者没有子结点
            {
                temp=n;
                if(!n->left)//没有左孩子或没有子结点
                    n=n->right;
                else
                    n=n->right;
                delete temp;
            }
        }
        return n;
    }
}
以右子树最小结点代替当前结点
N DeleteX(N n,int x)//删除某个元素(以右子树最小结点代替当前结点)
{
    if(!n)
    {
        cout<<"树中没有该元素,无法进行删除操作。"<<endl;
        return NULL;
    }
    else
    {
        if(x<n->data)
            n->left=DeleteX(n->left,x);
        else if(x>n->data)
            n->right=DeleteX(n->right,x);
        else//要删除的是当前结点
        {
            N temp;
            if(n->left&&n->right)//有左右两棵子树
            {
                temp=FindMin(n->right);
                n->data=temp->data;
                n->right=DeleteX(n->right,n->data);
            }
            else //只有一个子结点或者没有子结点
            {
                temp=n;
                if(!n->left)//没有左孩子或没有子结点
                    n=n->right;
                else
                    n=n->right;
                delete temp;
            }
        }
        return n;
    }
}

这是自己写的用于测试函数的数据,仅供参考。

测试数据

在输入的时候以换行分隔:8,3,12,1,5,0,15,0,0,4,7,0,0,0,0,0,0。一定要注意空结点。
二叉搜索树测试数据

测试程序

函数定义可见之前介绍。

int main()
{
    N tree;
    tree=CreateBinTree();
    StoryBrowse(tree);
    N temp;
    //temp=FindX(tree,5);
    temp=Findx(tree,5);
    cout<<endl;
    cout<<temp->data<<endl;
    cout<<"-------------------------------"<<endl;
    temp=FindMax(tree);
    cout<<temp->data<<endl;
    cout<<"-------------------------------"<<endl;
    temp=FindMin(tree);
    cout<<temp->data<<endl;
    cout<<"-------------------------------"<<endl;
    tree=Insert(tree,2);
    StoryBrowse(tree);
    cout<<endl;
    tree=DeleteX(tree,3);
    StoryBrowse(tree);
    cout<<endl;
    return 0;
}

参考文献:《数据结构(第2版)》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值