数据结构课实验一:树形结构
实验内容:
树型结构的遍历是树型结构算法的基础,本实验要求编写程序演示二叉树的存储结构的建立方法和遍历过程。
- 编写建立二叉树的二叉链表存储结构(左右链表示)的程序,并以适当的形式显示和保存二叉树;
- 采用二叉树的二叉链表存储结构,编写程序实现二叉树的先序、中序和后序遍历的递归和非递归算法以及层序遍历算法,并以适当的形式显示和保存二叉树及其相应的遍历序列;
- 给定一个二叉树, 编写算法完成下列应用:(二选一)
a) 判断其是否为完全二叉树;
b) 求二叉树中任意两个结点的公共祖先。
#include<cstdio>
#include<iostream>
using namespace std;
int height=-1;//树的层高
struct node
{
node *lchild,*rchild;
char data;
bool Isfirst=true;
};
typedef node *BTREE;
//栈的型
struct node1
{
BTREE stackval;
node1 *next;
};
typedef node1 * STACK;
//队列的型
struct celltype
{
BTREE queueval;
celltype *next;
};
struct QUEUE
{
celltype *front;
celltype *rear;
};
bool IsEmpty(BTREE &T)
{
if (!T)
return true;//空
else return false;
}
/*BTREE CreatBT(int v,BTREE ltree,BTREE rtree)
{
BTREE root=new node;
root->data=v;
root->lchild=ltree;
root->rchild=rtree;
return root;
}*/
//栈的基本操作
void MakeNull(STACK &S)
{
S=new node1;
S->next=NULL;
}
BTREE Top(STACK S)
{
if (S->next)
return (S->next->stackval);
else return NULL;///
}
void Pop(STACK &S)
{
STACK STK;
if (S->next)
{
STK=S->next;
S->next=STK->next;
delete STK;
}
}
void Push(BTREE x,STACK S)
{
STACK STK;
STK=new node1;
STK->stackval=x;
STK->next=S->next;
S->next=STK;
}
bool Empty(STACK S)
{
if(S->next)
return false;
else return true;
}
//队列的基本操作
void MakeNullQueue(QUEUE &Q)
{
Q.front=new celltype;
Q.front->next=NULL;
Q.rear=Q.front;
}
BTREE Front(QUEUE Q)
{
if(Q.front->next)
return Q.front->next->queueval;
else
return NULL; //
}
void EnQueue(BTREE x,QUEUE &Q)
{
Q.rear->next=new celltype;
Q.rear=Q.rear->next;
Q.rear->queueval=x;
Q.rear->next=NULL;
}
bool EmptyQ(QUEUE Q)
{
if (Q.front==Q.rear)
return true;
else
return false;
}
void DeQueue(QUEUE &Q)
{
celltype *tmp;
if (EmptyQ(Q))
cout<<"Queue is Empty!"<<endl;
else
{
tmp=Q.front->next;
Q.front->next=tmp->next;
delete tmp;
if (Q.front->next==NULL)
Q.rear=Q.front;
}
}
//构造一棵二叉树
void DevelopBT(BTREE &BT,int h)
{
char ch;
cin>>ch;
if (ch=='#')BT=NULL;
else
{
BT=new node;
if (BT==NULL){printf("没有足够的内存!");exit(0);}
BT->data=ch;
DevelopBT(BT->lchild,h+1);
DevelopBT(BT->rchild,h+1);
}
if(h>height)height=h;
}
//前序遍历二叉树-递归
void Preorder(BTREE &T)
{
if (T==NULL)return ;
cout<<T->data<<" ";
Preorder(T->lchild);
Preorder(T->rchild);
}
//非递归- 先输出根节点,再将此时的右节点入栈,先遍历左节点后再让右节点出栈
void NPreorder(BTREE &T)
{
STACK S; BTREE BT;
MakeNull(S);
BT=T;
while(!IsEmpty(BT)||!Empty(S))
if (!IsEmpty(BT))
{
cout<<BT->data<<" ";
if (BT->rchild)
Push(BT->rchild,S);
BT=BT->lchild;
}
else
{
BT=Top(S);Pop(S);
}
}
//中序遍历二叉树-递归
void Inorder(BTREE &T)
{
if (T==NULL)return ;
Inorder(T->lchild);
cout<<T->data<<" ";
Inorder(T->rchild);
}
//非递归-先入栈,递归遍历左孩子后将根节点出栈,递归遍历右节点
void NInorder(BTREE &T)
{
STACK S; BTREE BT;
MakeNull(S);
BT=T;
while(!IsEmpty(BT)||!Empty(S))
if (!IsEmpty(BT))
{
Push(BT,S);
BT=BT->lchild;
}
else
{
BT=Top(S);Pop(S);
cout<<BT->data<<" ";
BT=BT->rchild;
}
}
//后序遍历二叉树-递归
void Postorder(BTREE &T)
{
if (T==NULL)return ;
Postorder(T->lchild);
Postorder(T->rchild);
cout<<T->data<<" ";
}
//非递归-第二次到栈口时才能出栈
void NPostorder(BTREE &T)
{
STACK S; BTREE BT;
MakeNull(S);
BT=T;
while(!IsEmpty(BT)||!Empty(S))
if (!IsEmpty(BT))
{
Push(BT,S);
BT=BT->lchild;
}
else
{
BT=Top(S);Pop(S);
if (BT->Isfirst)
{
BT->Isfirst=false;
Push(BT,S);
BT=BT->rchild;
}
else
{
cout<<BT->data<<" ";
BT=NULL;
}
}
}
//层序遍历,利用队列、
void Levelorder(BTREE &T)
{
QUEUE Q;BTREE BT;
MakeNullQueue(Q);
BT=T;
EnQueue(BT,Q);
do
{
if (EmptyQ(Q))break;
BT=Front(Q);DeQueue(Q);
cout<<BT->data<<" ";
if (BT->lchild)
EnQueue(BT->lchild,Q);
if (BT->rchild)
EnQueue(BT->rchild,Q);
}while(1);
}
//判断是否为完全二叉树
/* 层序遍历先找到第一个不完全结点
如果该不完全结点没有左子树只有右子树那么一定不是完全二叉树,否则需进一步判断
在找到第一个不完全结点的前提下,如果之后的结点仍有左右子树则不是完全二叉树
*/
bool Fully(BTREE &T)
{
int Unfully=0;
QUEUE Q;BTREE BT;
MakeNullQueue(Q);
BT=T;
EnQueue(BT,Q);
do
{
if (EmptyQ(Q))break;
BT=Front(Q);DeQueue(Q);
switch(Unfully)
{
case 0:
{
if (BT->lchild)
EnQueue(BT->lchild,Q);
else{ Unfully=1;EnQueue(BT->lchild,Q);}
if (BT->rchild&&!BT->lchild) return false;
else if (BT->rchild&&BT->lchild)
EnQueue(BT->rchild,Q);
else{ Unfully=1;EnQueue(BT->lchild,Q);}
}
break;
case 1:
{
if (BT->lchild||BT->rchild)return false;
}
}
}while(1);
}
//寻找两个结点的最近公共祖先
/*
把两个结点的所有祖先按从最年轻(自己)到最老(根节点)的顺序存储
设定两个指针一开始均指向根节点
当两节点指向不同的祖先时,上一个相同的结点即为最近的公共祖先
*/
int flag=0;
char firstch[10001],secondch[10001];
// 把两个结点的所有祖先按从最年轻(自己)到最老(根节点)的顺序存储
int Getancestor(BTREE &T,char ch,char cch[],int cnt)
{
if (!T)return cnt;
if (T->data==ch) {cch[++cnt]=T->data;flag=1;return cnt;}
if (!flag)cnt=Getancestor(T->lchild,ch,cch,cnt);
if (!flag)cnt=Getancestor(T->rchild,ch,cch,cnt);
if (flag){cch[++cnt]=T->data;return cnt;}
return cnt;
}
//寻找最近公共祖先的主体部分
void Ancestor(BTREE &T)
{
char ch1,ch2;
cout<<"请输入要查找的两个结点!\n";
cin>>ch1>>ch2;
int cnt1=-1,cnt2=-1;
cnt1=Getancestor(T,ch1,firstch,0);
flag=0;
cnt2=Getancestor(T,ch2,secondch,0);
while(cnt1&&cnt2)
{
if(firstch[cnt1]==secondch[cnt2]){cnt1--;cnt2--;}
else break;
}
cout<<endl<<ch1<<"和"<<ch2<<"最近的公共祖先为"<<firstch[++cnt1]<<endl;
return ;
}
//菜单栏
void Menu(BTREE &T)
{
cout<<"菜单:\n1、前序遍历(递归)\n2、前序遍历(非递归)\n3、中序遍历(递归)\n4、中序遍历(非递归)\n5、后序遍历(递归)\n6、后序遍历(非递归)\n";
cout<<"7、层序遍历\n8、判断这棵树是否为完全二叉树\n9、求两个结点的最近的公共祖先\n10、退出程序\n";
cout<<"请键入需要进行的操作的序号:\n";
int x;
while(1)
{
cin>>x;
cout<<endl;
switch(x)
{
case 1: Preorder(T);
break;
case 2: NPreorder(T);
break;
case 3: Inorder(T);
break;
case 4: NInorder(T);
break;
case 5:Postorder(T);
break;
case 6:NPostorder(T);
break;
case 7:Levelorder(T);
break;
case 8:
{
bool t= Fully(T);
if (t)cout<<"此树是完全二叉树!\n";
else cout<< "此树不是完全二叉树!\n";
}
break;
case 9: Ancestor(T);
break;
case 10:
return ;
}
}
}
int main()
{
freopen("1.in","r",stdin);
node* root;
cout<<"请以前序遍历读入二叉树,用#表示二叉树每个结点的空子树";
DevelopBT(root,1);
Menu(root);
return 0;
}