任务概述:
(1)采用孩子双亲表示法,创建一棵一般的树,初始化树后添加孩子及其双亲结点,要求从键盘输入树中结点,并且结点数不少于五个;
(2)将树转成对应的二叉树,将结点的第一个孩子作为其左孩子,其余孩子作为其左孩子的右孩子;
(3)实现转换后二叉树的前序、中序、后序的递归遍历算法的实现;
(4)利用栈实现转换后二叉树的前序、中序、后序的非递归遍历算法的实现。
存储结构:
#include <stdio.h>
#include <stdlib.h>
#define OVERFLOW -2
#define OK 0
#define ERROR 0
#define STACK_INIT_SIZE 100//存储空间初始分配量
#define STACKINCREMENT 10//存储空间分配增量
#define MAX_TREE_SIZE 21//树的结点数目最大值
//>>>>>>>>>>>>>>>>>>>>>>>>>>>自定义数据类型<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
typedef int Status;//函数返回值状态码类型
typedef char ElemType;//树中结点元素类型
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>结构体定义<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//孩子结构
typedef struct CTNode
{
int child;//孩子结点的下标
struct CTNode *next;//指向下一个结点的指针
}*ChildPtr;
//表头结构
typedef struct
{
ElemType data;//存放在树中的结点的数据
int parent;//存放双亲的下标
ChildPtr firstchild;//指向第一个孩子的指针
}CTBox;
//树结构
typedef struct
{
CTBox tree[MAX_TREE_SIZE];//结点数组
int n;//结点数目
}CTree;
//二叉树结点,左孩子,右孩子
typedef struct BTNode
{
ElemType data;
struct BTNode *lchild,*rchild;
}BTNode,*BTree;
typedef BTree SElemType;
//栈的结构体
typedef struct{
SElemType *base;//在栈构造和销毁之后,base的值为NULL
SElemType *top;//栈顶指针
int stacksize;//当前已分配的存储空间
}Stack;
//--------------------------------1.采用孩子双亲表示法创建一棵一般的树-------------------------------
void InitCtree(CTree &T)
{//初始化树
int i;
printf("请输入树的结点个数:");
scanf("\n%d",&T.n);
printf("依次输入各个结点:\n");
for(i=0; i<T.n; i++)
{
fflush(stdin);//清理标准输入流,把多余的未被保存的数据丢掉
T.tree[i].data = getchar();
T.tree[i].parent = 0;
T.tree[i].firstchild = NULL;
}
}
void AddChild(CTree &T)
{//添加孩子
int i,j,k;
printf("-----------------------添加孩子及其双亲结点------------------------------------------\n");
for(k=0; k<T.n; k++)
{
fflush(stdin); //清理标准输入流,把多余的未被保存的数据丢掉
printf("请输入孩子结点及其双亲结点的序号:(用空格隔开)\n");
scanf("%d %d",&i,&j);
fflush(stdin);
CTNode *p = (CTNode *)malloc(sizeof(CTNode));
p->child = i;
p->next = NULL;
T.tree[i].parent = j;//找到双亲
if(!T.tree[j].firstchild)
T.tree[j].firstchild = p;
else
{
CTNode *temp = T.tree[j].firstchild;
while(temp->next )
temp = temp->next ;
temp->next = p;
}
}
}
//---------------------------------------2.将树转换成对应的二叉树------------------------------------------
Status ExchangeTree(BTree &BT,CTree &T)
{
BTNode *p,*q,*t,*pre;//pre指向p的双亲结点
CTNode *temp;
int m=T.n ;
if(!(p=(BTNode*)malloc(sizeof(BTNode))))
exit (OVERFLOW);
int i=0;
p->data =T.tree [i].data;
p->lchild =NULL;
p->rchild =NULL;
BT=p;
for(i=0;i<m;i++)
{
if(p->data !=T.tree [i].data)
{
if(!p->lchild &&!p->rchild )
p=pre;//p没有孩子时,p指向双亲结点
if(p->lchild )
{
if(T.tree [i].data==p->lchild->data )
pre=p;
p=p->lchild ;
}
if(p->rchild )
if(T.tree [i].data==p->rchild ->data)
pre=p;
p=p->rchild ;
}//寻找要转化的根结点 ,让p指向此时要转换的根节点
if(T.tree [i].firstchild)
{
int k=T.tree [i].firstchild->child;
q=(BTNode*)malloc(sizeof(BTNode));//为第一个孩子即左孩子分配空间
q->data =T.tree [k].data;
q->lchild =NULL;
q->rchild =NULL;
p->lchild =q;//p指向其左孩子
temp=T.tree [i].firstchild;
while(temp->next )//判断是否有兄弟结点
{
t=(BTNode*)malloc(sizeof(BTNode));
int s=temp->next ->child;
t->data =T.tree [s].data;
t->lchild =NULL;
t->rchild =NULL;
q->rchild =t;//右孩子为其兄弟结点
q=q->rchild ;
temp=temp->next ; //后移判断是否还有兄弟结点
}
}
}
}
//-------------------------------------3.遍历二叉树的递归算法-----------------------------------------------
/*先序遍历的递归算法*/
void PreOrderTraverse(BTree BT)
{
if(BT){
printf("%c ",BT->data );
PreOrderTraverse(BT->lchild );
PreOrderTraverse(BT->rchild );
}
}
/*中序遍历的递归算法*/
void InOrderTraverse(BTree BT)
{
if(BT){
InOrderTraverse(BT->lchild );
printf("%c ",BT->data );
InOrderTraverse(BT->rchild );
}
}
/*后序遍历的递归算法*/
void PostOrderTraverse(BTree BT)
{
if(BT){
PostOrderTraverse(BT->lchild );
PostOrderTraverse(BT->rchild );
printf("%c ",BT->data );
}
}
//----------------------------------------4.遍历的非递归算法--------------------------------------------------
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>栈的相关算法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Status InitStack(Stack &S){
//构造一个空栈
S.base =(SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType));
if(!S.base ) exit(OVERFLOW);
S.top =S.base ;
S.stacksize = STACK_INIT_SIZE;
return OK;
}
Status Push(Stack &S,SElemType e)
{
//入栈
if(S.top -S.base >=S.stacksize ){
//栈满
S.base =(SElemType*)realloc(S.base ,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));
if(!S.base ) exit (OVERFLOW);
S.top =S.base +S.stacksize ;
S.stacksize += STACKINCREMENT;
}
*S.top++=e;
return OK;
}
Status Pop(Stack &S,SElemType &e){
//出栈
if(S.top ==S.base ) return ERROR;
e=*--S.top ;
return OK;
}
Status GetTop(Stack S,SElemType &e)
{//若栈不空,则用e返回S的栈顶元素,并返回OK,否则返回ERROR
if(S.top ==S.base ) return ERROR;
e=*(S.top -1);
return OK;
}
Status StackEmpty(Stack S){
return (S.base ==S.top )?true:false;
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>栈的相关算法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>遍历的非递归算法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/*先序遍历的非递归算法*/
void PreOrder(BTree BT)
{
Stack S;
BTree p=BT;
InitStack(S);
while(p||!StackEmpty(S))
{
if(p)
{
Push(S,p);
printf("%c ",p->data );
p=p->lchild ;
}
else
{
Pop(S,p );
p=p->rchild ;
}
}
}
/*中序遍历的非递归算法*/
void InOrder(BTree BT)
{
Stack S;
BTree p=BT;
InitStack(S);
while(p||!StackEmpty(S))
{
if(p)
{
Push(S,p );
p=p->lchild ;
}
else
{
Pop(S,p );
printf("%c ",p->data );
p=p->rchild ;
}
}
}
/*后序遍历的非递归算法*/
/*步骤:
对于树中任意一个访问的节点p可以分情况讨论
1. p如果是叶子节点,直接输出
2. p如果有孩子,且孩子没有被访问过,则按照右孩子,左孩子的顺序依次入栈
3. p如果有孩子,而且孩子都已经访问过,则访问p节点*/
void PostOrder(BTree BT)
{
Stack S;
SElemType e;
BTree p=BT;
BTree mark;
mark=p;
InitStack(S);
Push(S,p);
while(!StackEmpty(S))
{
GetTop(S,p);//p等于栈顶指针
if( (p->lchild == NULL && p->rchild == NULL) || (p->rchild == NULL && mark == p->lchild ) || (mark == p->rchild ) )
//入栈时按照右孩子,左孩子顺序入栈,则右孩子被标记,左孩子没有或被标记
{
printf("%c ",p->data );
mark=p;
Pop(S,p);
}
else
{
if(p->rchild )
Push(S,p->rchild );
if(p->lchild )
Push(S,p->lchild );
}
}
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>遍历的非递归算法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//----------------------------------------------主函数--------------------------------------------------------------
main()
{
BTree BT;
CTree T;
SElemType e;
printf("--------------------------孩子双亲表示法表示一棵一般的树---------------------------\n");
InitCtree(T);
AddChild(T);
printf("---------------------------------树的创建已完成-------------------------------------\n");
ExchangeTree(BT,T);
printf("-------------------------------二叉树的转换已完成-----------------------------------\n");
printf("------------------------------二叉树的递归遍历算法----------------------------------\n");
printf("前序遍历:");
PreOrderTraverse(BT);
printf("\n");
printf("中序遍历:");
InOrderTraverse(BT);
printf("\n");
printf("后序遍历:");
PostOrderTraverse(BT);
printf("\n");
printf("------------------------------二叉树的非递归遍历算法---------------------------------\n");
printf("前序遍历:");
PreOrder(BT);
printf("\n");
printf("中序遍历:");
InOrder(BT);
printf("\n");
printf("后序遍历:");
PostOrder(BT);
printf("\n");
return 0;
}
运行结果: