/**
* 实验题目:
* 由遍历序列构造二叉树(逆向思维)
* 实验内容:
* 设计程序,实现由先序序列和中序序列以及由中序序列和后序序列构造
* 一棵二叉树的功能(二叉树中每个结点值为单个字符)。要求以括号表示法和
* 凹入表示法输出该二叉树。并用先序遍历序列"A B D E H J K L M N C F G I"
* 和中序遍历序列"D B J H L K M N E A F C G I"以及中序遍历序列"D B J H
* L K M N E A F C G I"和后序遍历序列"D J L N M K H E B F I G C A"进行验证。
*/
#include <stdio.h>
#include <malloc.h>
#define MaxSize 100
#define MaxWidth 50
typedef char ElemType;
typedef struct node
{
ElemType data; // 数据元素
struct node *lchild; // 指向左孩子结点
struct node *rchild; // 指向右孩子结点
}BTNode; // 声明二叉链结点类型
/*-------------由括号表示串str创建二叉链b-----------------*/
// char *str = "A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))";
void CreateBTNode(BTNode *&b, char *str)
{
BTNode *p = NULL;
BTNode *St[MaxSize];
int top = -1;
int k;
int j = 0;
char ch;
b = NULL;
ch = str[j];
// printf("start %s, ch = %c\n", __func__, ch);
while(ch != '\0')
{
switch(ch)
{
case '(':
top++;
St[top] = p;
k = 1;
break;
case ')':
top--;
break;
case ',':
k = 2;
break;
default:
p = (BTNode *)malloc(sizeof(BTNode));
p->data = ch;
p->lchild = p->rchild = NULL;
if(b == NULL)
b = p;
else
{
switch(k)
{
case 1:
St[top]->lchild = p;
break;
case 2:
St[top]->rchild = p;
break;
}
}
break;
}
j++;
ch = str[j];
// printf("%s, ch = %c\n", __func__, ch);
}
}
/*--------------------------以括号表示法输出一棵二叉树b----------------------*/
// "A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))"
void DispBTNode(BTNode *b)
{
if(b != NULL)
{
printf("%c", b->data);
if((b->lchild != NULL) || (b->rchild != NULL))
{
printf("(");
DispBTNode(b->lchild);
if(b->rchild != NULL)
printf(",");
DispBTNode(b->rchild);
printf(")");
}
}
}
/*--------------------------释放二叉树b的所有结点----------------------*/
void DestroyBTree(BTNode *&b) // 销毁二叉树(形参b:指针的引用)
{
if(b != NULL)
{
DestroyBTree(b->lchild);
DestroyBTree(b->rchild);
free(b);
}
}
//ElemType pre[] = "ABDEHJKLMNCFGI"; 先根遍历序列
//ElemType in[] = "DBJHLKMNEAFCGI"; 中根遍历序列
/*--------------------------由先根和中根遍历序列构造一棵二叉树----------------------*/
BTNode *CreateBT1(char *pre, char *in, int n)
{
BTNode *s;
char *p;
int k;
if(n <= 0)
return NULL;
s = (BTNode *)malloc(sizeof(BTNode)); // 创建二叉树结点s
s->data = *pre;
/*---------------------在中根遍历序列中寻找等于*pre的位置k---------------------*/
for(p = in; p < in + n; p++)
{
if(*p == *pre)
{
break;
}
}
k = p - in;
s->lchild = CreateBT1(pre + 1, in, k);
s->rchild = CreateBT1(pre + k + 1, p + 1, n - k -1);
return s;
}
/*--------------------------以凹入表示法输出一棵二叉树b----------------------*/
void DispBTNode1(BTNode *b)
{
BTNode *p;
BTNode *St[MaxSize]; // 栈(指针数组)
int top = -1; // 栈指针
int level[MaxSize][2];
char type; // 二叉树结点类型
int i; // 循环变量
int n; // 显示场宽,字符以右对齐显示,最左边输出空格的宽度
int width = 4;
if(b != NULL)
{
top++;
St[top] = b; // 根结点入栈
level[top][0] = width;
level[top][1] = 2; // 2表示根
while(top > -1)
{
p = St[top]; // 出栈并凹入显示该结点的值
n = level[top][0];
switch(level[top][1])
{
case 0: // 左结点之后输出(L)
type = 'L';
break;
case 1: // 右结点之后输出(R)
type = 'R';
break;
case 2: // 根结点之后输出(B)
type = 'B';
break;
}
/*------------------其中n为显示场宽,字符以右对齐显示-------------------*/
for(i = 1; i <= n; i++)
printf(" "); // 1、最左边从左到右输出空格个数
printf("%c(%c)", p->data, type); // 2、输出二叉树结点和类型
for(i = n + 1; i <= MaxWidth; i += 2)
printf("--"); // 3、后面以--补齐
printf("\n");
top--; // 栈指针减1
if(p->rchild != NULL)
{
top++;
St[top] = p->rchild; // 将右子树根结点入栈
level[top][0] = n + width; // 显示场宽增width
level[top][1] = 1; // 1表示右子树
}
if(p->lchild != NULL)
{
top++;
St[top] = p->lchild; // 将左子树根结点入栈
level[top][0] = n + width; // 显示场宽增width
level[top][1] = 0; // 0表示左子树
}
}
}
}
//ElemType in[] = "DBJHLKMNEAFCGI"; 中根遍历序列
//ElemType post[] = "DJLNMKHEBFIGCA"; 后根遍历序列
/*--------------------------由中根和后根遍历序列构造一棵二叉树----------------------*/
BTNode *CreateBT2(char *post, char *in, int n, int m)
{
BTNode *s;
char *p;
char *q;
char *maxp;
int maxpost;
int maxin;
int k; // 记录in中的每个字符在post中的位置下标
if(n <= 0 || m <= 0) // 参数错误检查
return NULL;
maxpost = -1;
for(p = in; p < in + n; p++) // 求in中的每个字符在post中的位置下标
{
for(q = post; q < post + m; q++)
{
if(*p == *q)
{
k = q - post;
//printf("%s, k = %d\n", __func__, k);
if(k > maxpost)
{
maxpost = k;
maxp = p;
maxin = p - in;
}
}
}
}
s = (BTNode *)malloc(sizeof(BTNode)); // 创建二叉树结点s
s->data = post[maxpost]; // 数据域
s->lchild = CreateBT2(post, in, maxin, m);
s->rchild = CreateBT2(post, maxp + 1, n - maxin - 1, m);
return s;
}
int main(void)
{
BTNode *b;
ElemType pre[] = "ABDEHJKLMNCFGI";
ElemType in[] = "DBJHLKMNEAFCGI";
ElemType post[] = "DJLNMKHEBFIGCA";
b = CreateBT1(pre, in, 14);
printf("先序序列:%s\n", pre);
printf("中序序列:%s\n", in);
printf("构造一棵二叉树b:\n");
printf(" 括号表示法:");
DispBTNode(b);
printf("\n");
printf(" 凹入表示法:\n");
DispBTNode1(b);
printf("\n");
printf("中序序列:%s\n", in);
printf("后序序列:%s\n", post);
b = CreateBT2(post, in, 14, 14);
printf("构造一棵二叉树b:\n");
printf(" 括号表示法:");
DispBTNode(b);
printf("\n");
printf(" 凹入表示法:\n");
DispBTNode1(b);
printf("\n");
return 0;
}
测试结果:
先序序列:ABDEHJKLMNCFGI
中序序列:DBJHLKMNEAFCGI
构造一棵二叉树b:
括号表示法:A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))
凹入表示法:
A(B)----------------------------------------------
B(L)------------------------------------------
D(L)--------------------------------------
E(R)--------------------------------------
H(L)----------------------------------
J(L)------------------------------
K(R)------------------------------
L(L)--------------------------
M(R)--------------------------
N(R)----------------------
C(R)------------------------------------------
F(L)--------------------------------------
G(R)--------------------------------------
I(R)----------------------------------
中序序列:DBJHLKMNEAFCGI
后序序列:DJLNMKHEBFIGCA
构造一棵二叉树b:
括号表示法:A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))
凹入表示法:
A(B)----------------------------------------------
B(L)------------------------------------------
D(L)--------------------------------------
E(R)--------------------------------------
H(L)----------------------------------
J(L)------------------------------
K(R)------------------------------
L(L)--------------------------
M(R)--------------------------
N(R)----------------------
C(R)------------------------------------------
F(L)--------------------------------------
G(R)--------------------------------------
I(R)----------------------------------