动态查找(查找,插入及删除)

看代码啦

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;

typedef struct Zl//二叉查找表的结点
{
    char data;//结点的值
    int count;//结点出现的次数
    Zl *lchild,*rchild;//左右孩子
}Zl;

bool Search(Zl *T,char key,Zl *f,Zl* &p)//查找操作
{
    if(T==NULL)//此时找不到
    {
        p=f;//记住最后访问的结点
        return false;
    }
    else if(T->data==key)//找到了
    {
        p=T;//记录找到的结点
        return true;
    }
    else if(T->data>key)//如果目标值小于当前值则到左子树进行查找
    {
        return Search(T->lchild,key,T,p);
    }
    else//大于则到右子树进行查找
    {
        return Search(T->rchild,key,T,p);
    }
}

bool Insert(Zl* &T,char elem)//插入操作,也是建立二叉查找树的操作
{
    Zl *p,*f;//p用来记住要找的结点,f指向当前节点的双亲结点
    p=NULL;
    f=NULL;
    if(Search(T,elem,f,p)==true)//找到了
    {
        p->count++;//个数加一
        return false;
    }
    else//没找到则插入
    {
        Zl *temp;
        temp=new Zl;
        temp->data=elem;
        temp->lchild=temp->rchild=NULL;
        temp->count=1;
        if(!p) T=temp;//数为空时直接将值赋给根节点
        else if(elem<p->data)//小于时则插入到左子树
        {
            p->lchild=temp;
        }
        else//大于时则插入到右子树
        {
            p->rchild=temp;
        }
        return true;
    }
}

bool Delete(Zl* &p)//删除p指针指向的结点
{
    Zl* q;
    if(p->lchild==NULL&&p->rchild==NULL)//既没有左子树也没有右子树时
    {
        q=p;
        p=NULL;
        free(q);
    }
    else if(p->lchild==NULL)//只有右子树时
    {
        q=p;
        p=p->rchild;//直接将p结点的右子树接到p结点的位置
        free(q);
    }
    else if(p->rchild==NULL)//只有左子树时
    {
        q=p;
        p=p->lchild;//直接将p结点的左子树接到p结点的位置
        free(q);
    }
    else//既有左子树也有右子树时
    {
        q=p;
        Zl *temp;
        temp=p->lchild;
        while(temp->rchild)//找到左子树中最右的结点,即中序遍历序列中上一个访问的结点
        {
            q=temp;
            temp=temp->rchild;
        }
        p->data=temp->data;//将根节点置为找到的结点,然后删除找到的结点,该节点一定没有右子树
        if(p!=q)
            q->rchild=temp->lchild;//将删除结点的左子树接到他的双亲结点的右子树上
        else//p=q时,说明p的左子树无右孩子,直接接上即可
            p->lchild=temp->lchild;
        free(temp);
    }
    return true;
}

bool DeleteBST(Zl* &T,char key)//删除树中所有等于key的结点
{
    if(!T) return false;
    else
    {
        if(T->data==key) return Delete(T);
        else if(T->data>key) return DeleteBST(T->lchild,key);
        else return DeleteBST(T->rchild,key);
    }
}



void MidOrderTraverse(Zl *p)//中序遍历输出
{
    if(p!=NULL)
    {
        MidOrderTraverse(p->lchild);
        cout<<'['<<p->data<<':'<<p->count<<']'<<endl;
        MidOrderTraverse(p->rchild);
    }
}

void XainOrderTraverse(Zl *p)//先序遍历输出
{
    if(p!=NULL)
    {
        cout<<'['<<p->data<<':'<<p->count<<']'<<endl;
        MidOrderTraverse(p->lchild);
        MidOrderTraverse(p->rchild);
    }
}

void HouOrderTraverse(Zl *p)//后序遍历输出
{
    if(p!=NULL)
    {
        MidOrderTraverse(p->lchild);
        MidOrderTraverse(p->rchild);
        cout<<'['<<p->data<<':'<<p->count<<']'<<endl;
    }
}

void Clean(Zl *first)//释放二叉查找树
{
    if(first!=NULL)
    {
        free(first);
        Clean(first->lchild);
        Clean(first->rchild);
    }
}

int main()
{
    Zl *T;
    T=NULL;
    char s[100];
    cout<<"请输入待统计的内容"<<endl;
    gets(s);//用gets接收来接收空格
    for(int i=0;i<strlen(s);i++)
    {
        Insert(T,s[i]);
    }
    DeleteBST(T,' ');
    cout<<"1.前序遍历输出"<<endl;
    cout<<"2.中序遍历输出"<<endl;
    cout<<"3.后序遍历输出"<<endl;
    cout<<"0.退出"<<endl;
    cout<<"请选择菜单项:"<<endl;
    int a;
    while(1)
    {
        cin>>a;
        if(a==1)
            XainOrderTraverse(T);
        else if(a==2)
            MidOrderTraverse(T);
        else if(a==3)
            HouOrderTraverse(T);
        else
            break;
    }

    Clean(T);
    return 0;
}

测试数据:

Every man loves what he is good at.

运行结果:
在这里插入图片描述

我的个人博客 amazingz6.github.io
我的CSDN https://blog.csdn.net/qq_44105654
我的简书 https://www.jianshu.com/u/607ef08e5825
我的github https://github.com/AmazingZ6?tab=repositories

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值