一、需求分析
1、遍历二叉树。
请输入一棵二叉树的扩展的前序序列,经过处理后生成一棵二叉树,然后对于该二叉树输出中序和后序遍历序列。
2、按层次遍历二叉树。
二、概要设计
- 程序中用到的抽象数据类型的定义:
typedef struct BiTNode
{ //二叉树结点结构定义
char data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
- 主程序的流程:
首先用fgets函数得到先序遍历序列,存入数组。用e指针指向数组首尾地址,使用CreateBiTree()函数建立二叉树,用root表示二叉树根结点。
其次建立中序输出函数InorderTraversal()和后序输出函数PostorderTraversal(),以及层序输出函数LevelorderBiTree(),依次输出结果。
最后使用DestroyBiTree()释放空间。
int main()
{
char PreOrder[MAXSIZE+1];
fgets(PreOrder, MAXSIZE, stdin);
char *e = PreOrder;
BiTree root = CreateBiTree(&e);
printf("中序遍历结果:");
InorderTraversal(root);
printf("\n");
printf("后序遍历结果:");
PostorderTraversal(root);
printf("\n");
printf("层序遍历结果:");
LevelorderBiTree(root);
printf("\n");
//释放空间
DestroyBiTree(root);
return 0;
}
三、详细设计
- 通过先序序列创建二叉树。
采用递归。
当e所指数组元素为“#”或者数组遍历结束,返回NULL,即空结点。
当e指向其他元素,创建新结点root,e移动到数组下一位,再递归构造root的左子树,和右子树。返回根结点。
BiTree CreateBiTree(char **e)
{
if(**e == '#' || **e == '\0')
{
(*e)++;
return NULL;
}
BiTree root;
root = CreateNode(**e);
(*e)++;
root->lchild = CreateBiTree(e); //递归构造左子树
root->rchild = CreateBiTree(e); //递归构造右子树
return root;
}
- 中序、后序遍历输出
中序、后序遍历函数思路相同,均是采用递归思想,不同之处在于,中序输出顺序为“左根右”,即先输出左子树,再输出根结点,最后输出右子树。后序输出顺序则是“左右根”。
//中序遍历
void InorderTraversal(BiTree root)
{
if(root == NULL) return;
InorderTraversal(root->lchild);
printf("%c", root->data);
InorderTraversal(root->rchild);
}
//后序遍历
void PostorderTraversal(BiTree root)
{
if(root == NULL) return;
PostorderTraversal(root->lchild);
PostorderTraversal(root->rchild);
printf("%c", root->data);
}
- 层序遍历输出
层序遍历采用队列储存二叉树结点,先是第一层根结点入队,其次第二层从左到右,根结点的左右子树入队。
用head记录当前队列对头,在输出队头元素时,再将该队头元素的左右子树入队。
//层序遍历
void LevelorderBiTree(BiTree root)
{
if(root == NULL) return;
BiTree queue[1000]; //用队列储存二叉树每层
int head = 0, tail = 0; //队列的头尾
BiTree p;
queue[tail++] = root; //根结点入队
while(head != tail)
{ //队列不空
p = queue[head++];
printf("%c", p->data);
if(p->lchild) queue[tail++] = p->lchild;
if(p->rchild) queue[tail++] = p->rchild;
}
}
四、调试分析
写代码时问题出现在建立二叉树上,我用数组存储先序输入序列,一开始想直接用PreOrder即数组首地址放入,即CreateBiTree(PreOrder),但由于数组首地址不可以更改,所以建立失败。解决方法:再建立一个指针指向数组。
int main()
{
char PreOrder[MAXSIZE+1];
fgets(PreOrder, MAXSIZE, stdin);
char *e = PreOrder;
BiTree root = CreateBiTree(&e);
//其他代码...
}
五、测试结果
输入:ABDG##HJ####CE#I##F##
输出:
附录
6、附录:带注释的源程序。
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
typedef struct BiTNode
{ //二叉树结点结构定义
char data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
//创建新结点
BiTree CreateNode(char data)
{
BiTree node = (BiTree)malloc(sizeof(BiTNode));
node->data = data;
node->lchild = NULL;
node->rchild = NULL;
return node;
}
//通过先序序列创建二叉树
BiTree CreateBiTree(char **e)
{
if(**e == '#' || **e == '\0')
{
(*e)++;
return NULL;
}
BiTree root;
root = CreateNode(**e);
(*e)++;
root->lchild = CreateBiTree(e); //递归构造左子树
root->rchild = CreateBiTree(e); //递归构造右子树
return root;
}
//中序遍历
void InorderTraversal(BiTree root)
{
if(root == NULL) return;
InorderTraversal(root->lchild);
printf("%c", root->data);
InorderTraversal(root->rchild);
}
//后序遍历
void PostorderTraversal(BiTree root)
{
if(root == NULL) return;
PostorderTraversal(root->lchild);
PostorderTraversal(root->rchild);
printf("%c", root->data);
}
//层序遍历
void LevelorderBiTree(BiTree root)
{
if(root == NULL) return;
BiTree queue[1000]; //用队列储存二叉树每层
int head = 0, tail = 0; //队列的头尾
BiTree p;
queue[tail++] = root; //根结点入队
while(head != tail)
{ //队列不空
p = queue[head++];
printf("%c", p->data);
if(p->lchild) queue[tail++] = p->lchild;
if(p->rchild) queue[tail++] = p->rchild;
}
}
//释放二叉树
void DestroyBiTree(BiTree root)
{
if(root == NULL) return;
DestroyBiTree(root->lchild);
DestroyBiTree(root->rchild);
free(root);
}
int main()
{
char PreOrder[MAXSIZE+1];
fgets(PreOrder, MAXSIZE, stdin);
char *e = PreOrder;
BiTree root = CreateBiTree(&e);
printf("中序遍历结果:");
InorderTraversal(root);
printf("\n");
printf("后序遍历结果:");
PostorderTraversal(root);
printf("\n");
printf("层序遍历结果:");
LevelorderBiTree(root);
printf("\n");
//释放空间
DestroyBiTree(root);
return 0;
}