二叉树操作:
实现以二叉链表为存储结构的二叉树的创建、遍历、查找、插入和删除操作。
说明:
1、按先序遍历思想创建二叉树;
2、分别实现中序遍历和层次遍历;
3、给定元素值查找结点指针位置并返回其指针,可利用指针引用data域输出;
4、实现插入左右孩子操作,指定元素值,找到结点后若已存在对应位置的孩子结点则不插入;
5、删除指定元素值的结点,若该结点存在子树则将其子树所有结点全部删除回收;
实现以二叉链表为存储结构的二叉树的创建、遍历、查找、插入和删除操作。
说明:
1、按先序遍历思想创建二叉树;
2、分别实现中序遍历和层次遍历;
3、给定元素值查找结点指针位置并返回其指针,可利用指针引用data域输出;
4、实现插入左右孩子操作,指定元素值,找到结点后若已存在对应位置的孩子结点则不插入;
5、删除指定元素值的结点,若该结点存在子树则将其子树所有结点全部删除回收;
6、程序提供简单功能菜单。
#include <iostream>
using namespace std;
//定义一个二叉树
typedef struct node
{
char date; //数据成员
struct node *lchild,*rchild;
} BTNode,*SecondTree;
//定义一个全局变量树
SecondTree seTree;
//定义全局变量,用来判断是否有此亲节点;
bool boolen=false;
//定义一个队,层次遍历时用
typedef struct Queue
{
char chardate;
struct Queue *next;
}* LQueue;
//判断队是否为空
bool isEmpaty(LQueue D);
//入队操作
void PushQueue(LQueue D,char pchar);
//出队函数,返回值char类型
char PopQueue(LQueue D);
//通过父节点,返回孩子节点
bool returnSun(SecondTree T,char f,char &sun1,char &sun2);
//层次遍历二叉树
void CengCi(SecondTree T);
//中序遍历二叉树
void MidTree(SecondTree Tree);
//先序遍历二叉树
void PreTree(SecondTree Tree);
//创建二叉树
void CreateBTNode(BTNode *);
//用先序遍历创建二叉树
//系统默认生成的广义表
//查找节点
bool findTree(SecondTree T,char f);
//插入节点
bool TreeInsert(SecondTree &T,char parent,char insert);
//删除节点
bool delNode(SecondTree &T,char delchar);
//主菜单
void Menu();
//导航栏
int MenuMethod();
int main()
{
MenuMethod();
return 0;
}
//创建二叉树
void CreateBTNode(BTNode *)
{
BTNode *&T=seTree;
cout<<endl<<"程序默认了一个以广义表形式构造的二叉树。无需手动输入。返回主菜单。"<<endl;
char c[19]="A(B(D(,G)),C(E,F))";
BTNode*St[10],*p;
int top=-1,k,j=0;
char ch;
T=NULL;
ch=c[j];
while(ch!='\0')
{
switch(ch)
{
case '(' :top++;St[top]=p;k=1;break;//开始处理左孩子节点
case ')' :top--;break;
case ',' :k=2;break;//开始处理右孩子节点
default :p=new BTNode;
p->date =ch;
p->lchild=p->rchild=NULL;
if(T==NULL)//尚未建立根节点
{
T=p;//*p为根节点
}
else
{
switch(k)
{
case 1:St[top]->lchild=p;break;
case 2:St[top]->rchild=p;break;
}
}
}
j++;
ch=c[j];
}
}
//查找节点元素 如果T中存在字符f则返回true,并打印出一句话”f 字符已找到!“。否则返回false
bool findTree(SecondTree T,char f)
{
SecondTree top=T;
if(T==NULL)
{
return false;
}
if(T->date!=f)
{
findTree(T->lchild, f);
findTree(T->rchild, f);
}
else
{
cout<<f<<" 字符已找到!!!!!"<<endl;
return true;
}
return false;
}
/*
插入节点元素,如果找不到要插入节点的双亲则返回false 找到结点后若已存在对应
位置的孩子结点则不插入返回false ,若找到结点后没有字节点 ,则插入节点元素返回true
*/
bool TreeInsert(SecondTree &T,char parent,char insert)
{
//SecondTree top=T;
BTNode *Jnode;
if(T==NULL)
{
return false;
cout<<"二叉树为空。"<<endl;
}
else if(T->date==parent )
{
boolen=true;
if (T->lchild!=NULL&&T->rchild!=NULL)
{
cout<<"左右孩子节点都已经存在。无须再插入。"<<endl;
return false;
}
else if (T->lchild==NULL)
{
Jnode=new node;
Jnode->date=insert;
Jnode->lchild=NULL;
Jnode->rchild=NULL;
T->lchild=Jnode;
cout <<"插入左孩子节点成功"<<endl;
return true;
}
else if(T->rchild==NULL)
{
Jnode=new node;
Jnode->date=insert;
Jnode->lchild=NULL;
Jnode->rchild=NULL;
T->rchild=Jnode;
cout <<"插入右孩子节点成功"<<endl;
return true;
}
}
else if(T->date!=parent)
{
TreeInsert(T->lchild,parent,insert);
TreeInsert(T->rchild,parent,insert);
}
return false;
}
//定义删除节点函数,第一个参数为指向树的指针,第二个参数为要删除的节点字符
bool delNode(SecondTree &T,char delchar)
{
if (T!=NULL)
{
//如果跟节点不为空
if (T->date==delchar)
{//如果根节点为要删除的节点···
cout<<"已找到节点!!下面执行删除"<<endl;
/**/
delete T->lchild;
T->lchild=NULL;
delete T->rchild;
T->rchild=NULL;
delete T;
T=new node;
T->lchild=NULL;
T->rchild=NULL;
return true;
}
else if (T->lchild!=NULL&&T->lchild->date==delchar)
{
//如果左孩子为要删除的节点
cout <<"删除左孩子:"<<endl;
delete T->lchild->lchild;
delete T->lchild->rchild;
delete T->lchild;
T->lchild=NULL;
return true;
}
else if (T->rchild!=NULL&&T->rchild->date==delchar)
{
//如果左孩子为要删除的节点
cout <<"删除右孩子:"<<endl;
delete T->rchild->lchild;
delete T->rchild->rchild;
delete T->rchild;
T->rchild=NULL;
return true;
}
else
{
if(T->lchild!=NULL)
{
//如果左孩子不为空
delNode(T->lchild,delchar);
}
if(T->rchild!=NULL)
{
//如果右孩子不为空
delNode(T->rchild,delchar);
}
}
}
return false;
}
//定义目录函数
void Menu(){
cout<<endl<<" 二叉树操作"<<endl;
cout<<endl;
cout<<"********************************************************************************";
cout <<endl<<"功能表: "<<endl<<endl;
cout <<" 1: 先序遍历创建树; 2: 中序遍历树;"<<endl<<endl;
cout <<" 3: 先序遍历树; 4: 层次遍历;"<<endl<<endl;
cout <<" 5: 插入节点; 6: 删除节点;"<<endl<<endl;
cout <<" 7: 查找节点; 8: 结束操作;"<<endl;
cout<<endl<<"********************************************************************************"<<endl;
}
int MenuMethod()
{
char Cnumber;
//输出目录
Menu();
cout <<endl<<"请您按键选择:"<<endl;
cin >>Cnumber;
while(Cnumber!=0)
{
switch(Cnumber)
{
case '1':
//先序遍历创建树
CreateBTNode(seTree);
break;
case '2':
cout<<"中序遍历结果:"<<endl;
MidTree(seTree);//调用中序遍历
cout<<"返回主菜单。"<<endl;
break;
case '3':
cout<<"先序遍历结果:"<<endl;
PreTree(seTree);//调用先序遍历
cout<<"返回主菜单。"<<endl;
break;
case '4':
//层次遍历
CengCi(seTree);
cout<<"返回主菜单。"<<endl;
break;
case '5':
//插入字符
char parent,insert;
cout<<"请输入你要插入字符的双亲:"<<endl;
cin>>parent;
cout<<"输入你要插入的字符"<<endl;
cin>>insert;
TreeInsert(seTree,parent,insert);
if(boolen==false)
{
cout<<"插入失败,不存在此双亲。,返回主菜单。"<<endl;
}
break;
case '6':
//删除节点
char delchar;
cout <<"请输入你要删除的节点字符:"<<endl;
cin >>delchar;
delNode(seTree,delchar);
cout<<"返回主菜单。"<<endl;
break;
case '7':
//调用查找树的节点函数
char f;
cout<<"请输入你要查找的字符"<<endl;
cin>>f;
findTree(seTree, f);
break;
case '8':
return 0;
break;
default :
//如果输入错误
cout <<"输入错误!!!请重新输入!"<<endl;
break;
}
Menu();//输出目录
cout <<endl<<"请输入你的选择:"<<endl;
cin >>Cnumber;
}
return 0;
}
//判断队是否为空
bool isEmpaty(LQueue D)
{
if (D->next==NULL)
{
return true;
}
else
return false;
}
//入队操作
void PushQueue(LQueue D,char pchar)
{
while (D->next!=NULL)
{
D=D->next;
}
D->next=new Queue;
D->next->chardate=pchar;
D->next->next=NULL;
}
//出队函数,返回值char类型
char PopQueue(LQueue D)
{
char pchar;
if(D->next!=NULL)
{
pchar=D->next->chardate;
}
else
{
pchar='#';
return pchar;
}
if (D->next->next!=NULL)
{
D->next=D->next->next;
}
else
{
D->next=NULL;
}
return pchar;
}
//通过父节点,返回孩子节点
bool returnSun(SecondTree T,char f,char &sun1,char &sun2)
{
SecondTree top=T;
if(T==NULL)
{
return false;
}
if(T->date!=f)
{
if (T->lchild!=NULL)
returnSun(T->lchild, f,sun1,sun2);
if (T->rchild!=NULL)
returnSun(T->rchild, f,sun1,sun2);
}
else
{
//cout<<f<<" 字符已找到lelelell!"<<endl;
if (T->lchild!=NULL)
{ //如果左孩子不为空,把其值储存到sun1中
sun1=T->lchild->date;
}
else
{
sun1='#';
}
if (T->rchild!=NULL)
{ //如右孩子不为空,把其值储存到sun2中
sun2=T->rchild->date;
}
else
{
sun2='#';
}
return true;
}
return false;
}
//层次遍历二叉树
void CengCi(SecondTree T)
{
SecondTree Top=T;
LQueue TopQueue;
TopQueue=new Queue;
cout<<endl<<"层次遍历二叉树: "<<endl;
TopQueue->next=NULL;
if (T!=NULL)
{ //如果头结点不为空,读出头结点。
cout <<T->date<<endl;
//如果左孩子不为空,入队
if (T->lchild!=NULL)
{
PushQueue(TopQueue,T->lchild->date);
}
//如果右孩子不为空,入队
if (T->rchild!=NULL)
{
PushQueue(TopQueue,T->rchild->date);
}
}
//while 队不为空,出队 ,读该节点,把孩子入队
char pchar;
char sun1,sun2;
if (!isEmpaty(TopQueue))
{
while (!isEmpaty(TopQueue))
{
//出队
pchar=PopQueue(TopQueue);
//找到pchar 读出它
cout<<pchar<<endl;
returnSun(T,pchar,sun1,sun2);//获得出队元素的左右孩子
if(sun1!='#')
{//左孩子不为空。则入队
PushQueue(TopQueue,sun1);
}
if(sun2!='#')
{//右孩子不为空。则入队
PushQueue(TopQueue,sun2);
}
}
}
}
//中序遍历二叉树
void MidTree(SecondTree Tree)
{
SecondTree top=Tree;
if(top!=NULL)
{ //如果节点不为空
MidTree(top->lchild); //先序遍历左子树
cout<<top->date<<endl;//输出节点数
MidTree(top->rchild);//先序遍历右子树
}
}
//先序遍历二叉树,参数为指向结构体变量的指针
void PreTree(SecondTree Tree)
{
SecondTree top=Tree;
if(top!=NULL)
{ //如果节点不为空
cout<<top->date<<endl;//输出节点数
PreTree(top->lchild); //先序遍历左子树
PreTree(top->rchild);//先序遍历右子树
}
}
输出结果: