二叉树实验
(一)用到的结构体
typedef struct node
{
char info;
struct node* lchild;
struct node* rchild;
}tree;
typedef struct stack_1
{
tree* a[MAX];
int tag[MAX];
int top;
}stack;
(二)对栈的操作
void push(stack* st, tree* t)
{
st->a[st->top] = t;
st->top++;
}
tree* pop(stack* st)
{
if (st->top != 0)
{
st->top--;
return st->a[st->top];
}
else
return NULL;
}
tree* top(stack* st)
{
if (st->top != 0)
{
return st->a[st->top - 1];
}
else
{
return NULL;
}
}
(三)递归建树
tree *creat()//递归建树
{
tree *root;
char ch;
scanf_s("%c", &ch,1);
if (ch == '#')
return NULL;
else
{
root = (tree*)malloc(sizeof(tree));
root->info = ch;
root->lchild = creat();
root->rchild = creat();
}
return root;
}
(四)非递归建树
tree *creat_1()//非递归建树
{
stack_1 A;
stack_1 *st;
st = &A;
tree *root;
tree *p1, *p2;
int i = 0;
char ch[MAX];
//0---左孩子为空,1---右孩子为空,2建树完成
scanf_s("%s", ch, MAX);
getchar();
st->top = 0;//栈初始化
while (ch[i] != '\0')
{
if (i == 0)//建立根节点
{
root = (tree*)malloc(sizeof(tree));
root->info = ch[i];
root->lchild = NULL;
root->rchild = NULL;
p1 = root;
push(st, root);
st->tag[st->top - 1] = 0;
}
else//非根节点
{
if (ch[i] != '#'&&st->tag[st->top - 1] == 0)//建左树
{
p2 = (tree*)malloc(sizeof(tree));
p2->info = ch[i];
p2->lchild = NULL;//一定要有,不然会和下面的代码冲突
p2->rchild = NULL;
push(st, p2);//入栈
p1->lchild = p2;//连接新建左孩子
p1 = p2;//指针下移
st->tag[st->top - 1] = 0;//0表示此节点没有左孩子
}
else if (ch[i] == '#'&&st->tag[st->top - 1] == 0)//左树完成
{
p1->lchild = NULL;
st->tag[st->top - 1] = 1;//左子树构建完成
}
else if (ch[i] == '#'&&st->tag[st->top - 1] == 1)//右树完成
{
p1->rchild = NULL;
st->tag[st->top - 1] = 2;//右子树构建完成
}
else if (ch[i] != '#'&&st->tag[st->top - 1] == 1)//建右树
{
p2 = (tree*)malloc(sizeof(tree));
p2->info = ch[i];
p2->lchild = NULL;
p2->rchild = NULL;
push(st, p2);
p1->rchild = p2;
p1 = p2;
st->tag[st->top - 1] = 0;
}
while (st->tag[st->top - 1] == 2)//是否出栈操作,当左右子树都已建立时,出栈
{
st->tag[st->top - 1] = 0;
p1 = pop(st);
if (st->top != 0)//避免最后一个节点误操作,如果没有此句,会导致栈的top越界
p1 = st->a[st->top - 1];
else
break;
if (st->tag[st->top - 1] == 1)//说明此时结点的左子树已存在,并且当前指针是从下一右子树返上来的结点,即:右子树也存在;
{
st->tag[st->top - 1] = 2;
}
}
if (p1->lchild != NULL || st->tag[st->top - 1] == 1)//对返上来的结点进行判断,有左子树则改变标记为1
{
st->tag[st->top - 1] = 1;
}
}
i++;
}
return root;
}
完整代码:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define MAX 1000
typedef struct node
{
char info;
struct node* lchild;
struct node* rchild;
}tree;
typedef struct stack_1
{
tree* a[MAX];
int tag[MAX];
int top;
}stack;
void push(stack* st, tree* t)
{
st->a[st->top] = t;
st->top++;
}
tree* pop(stack* st)
{
if (st->top != 0)
{
st->top--;
return st->a[st->top];
}
else
return NULL;
}
tree* top(stack* st)
{
if (st->top != 0)
{
return st->a[st->top - 1];
}
else
{
return NULL;
}
}
tree *creat()//递归建树
{
tree *root;
char ch;
scanf_s("%c", &ch,1);
if (ch == '#')
return NULL;
else
{
root = (tree*)malloc(sizeof(tree));
root->info = ch;
root->lchild = creat();
root->rchild = creat();
}
return root;
}
tree *creat_1()//非递归建树
{
stack_1 A;
stack_1 *st;
st = &A;
tree *root;
tree *p1, *p2;
int i = 0;
char ch[MAX];
//0---左孩子为空,1---右孩子为空,2建树完成
scanf_s("%s", ch, MAX);
getchar();
st->top = 0;//栈初始化
while (ch[i] != '\0')
{
if (i == 0)//建立根节点
{
root = (tree*)malloc(sizeof(tree));
root->info = ch[i];
root->lchild = NULL;
root->rchild = NULL;
p1 = root;
push(st, root);
st->tag[st->top - 1] = 0;
}
else//非根节点
{
if (ch[i] != '#'&&st->tag[st->top - 1] == 0)//建左树
{
p2 = (tree*)malloc(sizeof(tree));
p2->info = ch[i];
p2->lchild = NULL;//一定要有,不然会和下面的代码冲突
p2->rchild = NULL;
push(st, p2);//入栈
p1->lchild = p2;//连接新建左孩子
p1 = p2;//指针下移
st->tag[st->top - 1] = 0;//0表示此节点没有左孩子
}
else if (ch[i] == '#'&&st->tag[st->top - 1] == 0)//左树完成
{
p1->lchild = NULL;
st->tag[st->top - 1] = 1;//左子树构建完成
}
else if (ch[i] == '#'&&st->tag[st->top - 1] == 1)//右树完成
{
p1->rchild = NULL;
st->tag[st->top - 1] = 2;//右子树构建完成
}
else if (ch[i] != '#'&&st->tag[st->top - 1] == 1)//建右树
{
p2 = (tree*)malloc(sizeof(tree));
p2->info = ch[i];
p2->lchild = NULL;
p2->rchild = NULL;
push(st, p2);
p1->rchild = p2;
p1 = p2;
st->tag[st->top - 1] = 0;
}
while (st->tag[st->top - 1] == 2)//是否出栈操作,当左右子树都已建立时,出栈
{
st->tag[st->top - 1] = 0;
p1 = pop(st);
if (st->top != 0)//避免最后一个节点误操作,如果没有此句,会导致栈的top越界
p1 = st->a[st->top - 1];
else
break;
if (st->tag[st->top - 1] == 1)//说明此时结点的左子树已存在,并且当前指针是从下一右子树返上来的结点,即:右子树也存在;
{
st->tag[st->top - 1] = 2;
}
}
if (p1->lchild != NULL || st->tag[st->top - 1] == 1)//对返上来的结点进行判断,有左子树则改变标记为1
{
st->tag[st->top - 1] = 1;
}
}
i++;
}
return root;
}
void preprint(tree* t)//递归前序输出
{
tree* p1;
p1 = t;
if (!p1)
return;
else
{
printf("%c->", p1->info);
preprint(p1->lchild);
preprint(p1->rchild);
}
}
void inorprint(tree* t)
{
tree* p1;
p1 = t;
if (!p1)
return;
else
{
inorprint(p1->lchild);
printf("%c->", p1->info);
inorprint(p1->rchild);
}
}
void postprint(tree* t)
{
tree* p1;
p1 = t;
if (!p1)
return;
else
{
postprint(p1->lchild);
postprint(p1->rchild);
printf("%c->", p1->info);
}
}
void preprint_1(tree* t)//非递前序输出;
{
stack A;
stack* st;
st = &A;
tree* p1;
p1 = t;
st->top = 0;
while (p1 || st->top != 0)
{
if (p1)
{
printf("%c->", p1->info);
push(st, p1);
p1 = p1->lchild;
}
else {
p1 = pop(st);
p1 = p1->rchild;
}
}
}
void inorprint_1(tree* t) //非递归中序输出
{
stack B;
stack* st;
st = &B;
st->top = 0;
tree *p1;
p1 = t;
while (p1 || st->top != 0)
{
if (p1)
{
push(st, p1);
p1 = p1->lchild;
}
else
{
p1 = pop(st);
printf("%c-->", p1->info);
p1 = p1->rchild;
}
}
}
void postprint_1(tree* t)//非递归后序遍历
{
stack C;
stack* st;
st = &C;
st->top = 0;
tree* p1;
p1 = t;
while (p1 || st->top != 0)
{
if (p1)
{
push(st, p1);
st->tag[st->top-1] = 0;
p1 = p1->lchild;
}
else//空
{
if (st->tag[st->top-1] == 0)
{
p1 = st->a[st->top - 1];
st->tag[st->top - 1] = 1;
p1 = p1->rchild;
}
else if (st->tag[st->top-1] == 1)
{
p1 = st->a[st->top - 1];
printf("%c***->", p1->info);
st->tag[st->top - 1] = 0;
st->top--;
p1=NULL;//避免多次入栈
}
}
}
}
void fun()//输出递归菜单
{
printf("\n**************二叉树递归操作菜单***********\n");
printf("****“A”--------前序遍历二叉树--------****\n");
printf("****“B”--------中序遍历二叉树--------****\n");
printf("****“C”--------后序遍历二叉树--------****\n");
printf("****“D”---------本次执行结束---------****\n");
printf("*******************************************\n\n");
}
void fun_1()//输出非递归菜单
{
printf("\n*************二叉树非递归操作菜单**********\n");
printf("****“1”--------前序遍历二叉树--------****\n");
printf("****“2”--------中序遍历二叉树--------****\n");
printf("****“3”--------后序遍历二叉树--------****\n");
printf("****“4”---------本次执行结束---------****\n");
printf("*******************************************\n\n");
}
void fun2()
{
printf("\n*************二叉树操作菜单**********\n");
printf("****“d”--------递归操作--------****\n");
printf("****“f”-------非递归操作-------****\n");
printf("****“@”--------退出程序--------****\n");
printf("*************************************\n\n");
}
void fun3()
{
printf("\n*************二叉树建立菜单**********\n");
printf("****“q”--------递归建立--------****\n");
printf("****“w”-------非递归建立-------****\n");
printf("*************************************\n\n");
}
int getnode(tree *root)
{
if (root == NULL)
return 0;
else if (root->lchild == NULL&&root->rchild == NULL)
return 1;
else
return getnode(root->lchild) + getnode(root->rchild);
}
int getnode_1(tree *root)
{
stack A;
stack *st;
st = &A;
st->top = 0;
int sum = 0;
while (root || st->top != 0)
{
if (root)
{
if (root->lchild == NULL&&root->rchild == NULL)
sum++;
push(st, root);
root = root->lchild;
}
else
{
root = pop(st);//往上返一层
root = root->rchild;
}
}
return sum;
}
tree* getlastnode(tree * root)
{
tree *p;
p = root;
while (p&&p->rchild)
{
p = p->rchild;
}
return p;
}
tree* getfather(tree* t,char x,char y)
{ stack s;
tree *antor;
tree* data[100]={0};
int i=0,j;
s.top=-1;
while(t || s.top>-1)
{ while(t)
{
s.a[++s.top]=t;
s.tag[s.top]=0;
t=t->lchild;
}
while(s.top>-1 && s.tag[s.top])
{
t=s.a[s.top];
if(t->info==x)
while(i<=s.top) //记录x结点的所有祖先结点
{
data[i] = s.a[i];
i++;
}
else if(t->info==y)
{
while(s.top>-1)
{
j=i-1;
while(j>=0&&t!=data[j])//查找y与x的最近公共祖先结点
j--;
if(j>=0)
{
antor=data[j]; //返回公共祖先结点地址
return antor;
}
t=s.a[--s.top];
}
}
--s.top;
}
if(s.top>-1)
{
t=s.a[s.top];
s.tag[s.top]=1;
t=t->rchild;
}
else t=NULL;
}
}
int main()
{
tree* T=NULL;
char A, B;
tree* root;
char u;
char a;
root = NULL;
fun3();
printf("请选择以何种方式建立二叉树(递归和非递归):");
u = getchar();
getchar();
if (u == 'q')
{
printf("输入一组数据(以#分隔):\n");
root = creat();
getchar();
}
else if(u=='w')
{
printf("输入一组数据(以#分隔):\n");
root = creat_1();
}
int k = getnode_1(root);
printf("\n叶子节点:%d\n", k);
tree * p4 = getlastnode(root);
printf("中序的最后一个节点是:%c\n", p4->info);
printf("查找共同祖先(输入两个结点值):\n");
scanf_s("%c%c", &A, 1, &B, 1);
getchar();
tree* P=getfather(root, A, B);
printf("%c和%c的共同祖先是:", A, B);
printf("%c\n", P->info);
while (1)
{
char p;
printf("\n -----请选择操作类型-----\n");
fun2();
scanf_s("%c", &p, 1);
getchar();
if (p == 'd')
{
fun();
while (1)
{
a = getchar();
getchar();
if (a == 'A')
{
printf("前序遍历:"); preprint(root); printf("\n");
}
else if (a == 'B')
{
printf("中序遍历:"); inorprint(root); printf("\n");
}
else if (a == 'C')
{
printf("后序遍历:"); postprint(root); printf("\n");
}
else if(a=='D'){
break;
}
}
}
else if (p == 'f')
{
fun_1();
while (1)
{
a = getchar();
getchar();
if (a == '1')
{
printf("前序遍历:"); preprint_1(root); printf("\n");
}
else if (a == '2')
{
printf("中序遍历:"); inorprint_1(root); printf("\n");
}
else if (a == '3')
{
printf("后序遍历:"); postprint_1(root); printf("\n");
}
else if(a=='4') {
break;
}
}
}
else if (p == '@')
{
break;
}
else {
printf("********\n");
printf("**警告**:非法字符,请重新操作!\n");
printf("********\n");
}
}
return 0;
}
输入数据:
ABDH#K###E##CFI###G#J##
二叉树:
输出如下: