数据结构实现二叉排序树

摘  要

二叉排序树(Binary Search Tree,BST),又叫做二叉查找树,二叉搜索树,是一种对查找和排序都有用的特殊二叉树。因为二叉排序树的中序遍历有序性,即得到的递增的序列,由于有序,因此其查找与二分查找类似,每次都可以缩小查找范围,查询效率较高。同时因为二叉排序树的中序遍历存在有序性,所以首先要查找待插入元素的插入位置,当查找不成功时再将待插入元素作为新的叶子节点成为最后一个查找结点的左孩子或者右孩子。二叉排序树的创建可以从空树开始,按照插入关键字的顺序依次进行插入操作,最后得到一颗二叉排序树。二叉排序树的删除需要先在二叉排序树中找到待删除节点,然后执行删除操作。假设指针p指向待删除节点,指针f指向p的父节点。根据待删除节点所在位置的不同,删除操作的处理方法也不同。

关键词:二叉排序树  中序遍历  左孩子  右孩子  

  • 需求分析

1.1 课设主要研究问题

用顺序或二叉链表作为存储结构:

1) 以回车('\n')为输入结束标志,输入数列 L,生成一棵二叉排序树 T;

2) 对二叉排序树 T 作中序遍历,输出结果;

3) 输入元素x,查找二叉排序树T,若存在含x的结点,则删除该结点,并作中

序遍历(执行操作 2);否则输出信息“无 x”;

4) 以二叉排序树结构设计并实现一个排序算法

概要设计

2.1 课设应用的理论知识

二叉排序树或是一棵空树,或具有以下特征:

  1. 若左子树非空,其左子树上所有结点的值均小于根节点的值。
  2. 若右子树非空,其右子树上所有结点的值均大于根节点的值。
  3. 左右子树也满足二叉排序树的特性。
  4. 左子树结点值<根节点值<右子树结点值,所以如果对二叉排序树进行中序遍历可以得到一个递增的有序序列。

添加:从根节点开始往下寻找为null的位置插入结点。

删除:1、找到删除结点所在位置; 2、找到其中序遍历相邻节点; 3、将相邻结点的值赋给删除结点,删除相邻结点。               

2.2 程序流程图

详细设计

  建立二叉排序树采用边查找边插入的方式。查找函数采用递归的方式进行查找。如果查找到相等的则插入其左子树。否则返回当前结点的上一个结点,然后利用插入函数将该元素插入原树。对二叉树进行中序遍历采用递归函数的方式。在根结点不为空的情况下,先访问左子树,再访问根结点,最后访问右子树。删除结点函数,采用边查找边删除的方式。如果没有查找到进行提示如果查找到结点则将其左于树最右边的节点的数据传给它,然后删除其左子树最右边的节点。

程序主要设计了四个功能:首先是创建二叉排序树,完成后出现任务菜单,以数字代码确定,二叉排序树的中序遍历和查找,删除步骤,最后完成,结束。

对二叉树进行中序遍历采用递归函数的方式。在根结点不为空的情况下,先访问 左子树,再访问根结点,最后访问右子树。

删除结点函数,采用边查找边删除的方式。如果没有查找到,则不对树做任何的 修改;如果查找到结点,则分四种情况分别进行讨论:1、该结点左右子树均为空,那么令其右子树子承父业代替被删除节点的位置即可;2、该结点右子树为空,那么令其左子树子承父业代替被删除节点的位置即可;3、该结点左右子树均不为空,就不能采用子承父业的方法了,根据二叉排序树的中序遍历有序性删除该节点,可以利用其直接前驱或者直接后继来代替被删除节点的位置,然后删除其直接前驱或者直接后继即可。

直接前驱:在中序遍历中,节点p的直接前驱就是其左子树中的最右节点。即沿着p的左子树一直访问其右子树,直到没有右子树,这样就找到了最右节点,也就是直接前驱。

    直接后继:在中序遍历中,节点p的直接后继就是其右子树中的最左节点。即沿着p的右子树一直访问其左子树,直到没有左子树,这样就找到了最左节点,也就是直接后继。

在进行算法设计时,将题目分成以下五个模块:

1、中序遍历,符合升序输出

void inorder(node *&root)      

{

  if(root!=NULL)

  {

   inorder(root->left);

   cout<<root->data<<' ';

   inorder(root->right);

  }

 }

2、在查找树中插入元素

void insert(node *&ptr,int item)   

{

  if(ptr==NULL)

  ptr=new node(item);

  else if(item<ptr->data)

  insert(ptr->left,item);

  else insert(ptr->right,item);

 }

3、在查找树中查找元素 

node *find(node *&ptr,int item)   

{

     if(ptr==NULL)

         return NULL;

     if(ptr->data==item)

         return ptr;

     else if(item<ptr->data)

         find(ptr->left,item);

     else find(ptr->right,item);

 }

4、在查找树中查找肯定存在的元素,并返回其引用

node *&findy(node *&ptr,int item)  

 {

        if(ptr->data==item)

            return ptr;

        else if(item<ptr->data)

            findy(ptr->left,item);

        else findy(ptr->right,item);

 }

 node* rl()

{

return left;

}

 node* rr()

{

return right;

}

5、删除指定值为所在结点

void dele(node *&ptr)       

 {

  if(ptr->rl()==NULL&&ptr->rr()==NULL)

   ptr=NULL;

  else if(ptr->rr()==NULL)

   ptr=ptr->rl();

  else

   ptr=ptr->rr();

 }

private:

 int data;

 node *left;               

 node *right;              

};

完整程序代码

#include <iostream>
using namespace std;

class node
{
public:
node(int i):data(i),left(NULL),right(NULL){}
 void inorder(node *&root)      //中序遍历,符合升序输出
 {
  if(root!=NULL)
  {
   inorder(root->left);
      cout<<root->data<<' ';
      inorder(root->right);
  }
 }
 void insert(node *&ptr,int item)  //在查找树中插入元素
 {
  if(ptr==NULL)
   ptr=new node(item);
  else if(item<ptr->data)
   insert(ptr->left,item);
  else insert(ptr->right,item);
 }
 node *find(node *&ptr,int item)  //在查找树中查找元素,找到返回所在结点指针,找不到返回空指针。
 {
        if(ptr==NULL)
            return NULL;
        if(ptr->data==item)
            return ptr;
        else if(item<ptr->data)
            find(ptr->left,item);
        else find(ptr->right,item);
 }
 node *&findy(node *&ptr,int item)  //在查找树中查找肯定存在的元素,并返回其引用
 {
        if(ptr->data==item)
            return ptr;
        else if(item<ptr->data)
            findy(ptr->left,item);
        else findy(ptr->right,item);
 }
 node* rl(){return left;}
 node* rr(){return right;}

 void dele(node *&ptr)       //删除值为item所在结点
 {
  if(ptr->rl()==NULL&&ptr->rr()==NULL)
   ptr=NULL;
  else if(ptr->rr()==NULL)
   ptr=ptr->rl();
  else
   ptr=ptr->rr();
 }
private:
 int data;
 node *left;               //左孩子结点
 node *right;              //右孩子结点
};

int main()
{
 int t,i=0,j;
 cout<<"         二叉排序树的实现"<<endl;
 cout<<"1.二叉排序树T的输入:"<<endl;
 cout<<"输入数字个数(结点个数):";
 cin>>t;
 cout<<"输入"<<t<<"个数字,数字之间用空格隔开:";
 cin>>j;
 node *x=new node(j);
 for(;i<t-1;i++)
 {
  cin>>j;
  x->insert(x,j);
 }
 cout<<"中序遍历为:";
 x->inorder(x);               //作中序遍历
 cout<<"\n";
 cout<<"2.二叉排序树T的元素查找和删除:"<<endl;
 cout<<"\n输入操作(当输入0时程序结束):"<<endl;
 cin>>j;
 while(j!=0)
 {
  
   node *t=x->find(x,j);          //定位结点
   if(t!=NULL)
   {
    node *&y=x->findy(x,j);
    x->dele(y);
 cout<<"中序遍历为:";
 x->inorder(x);
   }
   else cout<<"无"<<j;
   cout<<"\n输入操作(当输入0时程序结束):"<<endl;
   cin>>j;
 }
 return 0;
}

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X-MTing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值