打印二叉树结构(设计性实验)
1. 需求分析
按凹入表形式横向打印二叉树结构,即二叉树的根在屏幕的左边,二叉树的左子树在屏幕的下边,二叉树的右子树在屏幕的上边。例如:测试数据由读者依据软件工程的测试技术自己确定。注意测试边界数据,如空二叉树。
实现提示
(1) 利用中序遍历方法。
(2) 利用结点的深度控制横向位置。
2. 概要设计
- 为了实现程序功能,需要定义树的抽象数据类型。
ADT BinaryTree{
数据对象D:D是具有相同特性的数据元素的集合
数据关系R:
若D = Φ,则R = Φ,称BinaryTree为空二叉树
若D ≠ Φ,则R = {H},H有如下二元关系:
(1)在D中存在唯一的称为根的数据元素root,它在关系H下无前驱;
(2)若D-{root} ≠ Φ,则存在D - {root} = {Dl,Dr},且Dl ∩ Dr = Φ;
(3)若Dl ≠ Φ,则Dl中存在唯一的元素xl,<root,xl>∈H,且存在Dl上的关系Hl⊂H;
若Dr ≠ Φ,则Dr中存在唯一的元素xr,<root,xr>∈H,且存在Dr上的关系Hr⊂H;
H = {<root,xl>,<root,xr>,Hl,Hr};
(4)(Dl,{Hl})是一棵符合本定义的二叉树,称为根的左子树,
(Dr,{Hr})是一棵符合本定义的二叉树,称为根的右子树;
typedef struct BiTNode{
elemtype data;
int deep;
struct BiTNode *lchild;
struct BiTNode *rchild;
}*bitree,bitnode; //树结构
基本操作P:
InitBiTree(&T);
操作结果:构造空的二叉树T。
DestoryBiTree(&T);
初始条件:二叉树T存在。
操作结构:销毁二叉树T。
CreateBiTree(&T,definition);
初始条件:definition给出二叉树T的定义。
操作结果:按definition构造二叉树T。
ClearBiTree(&T);
初始条件:二叉树T存在。
操作结果:将二叉树清为空树。
BiTreeEmpty(T);
初始条件:二叉树T存在。
操作结果:若T为空二叉树,返回TRUE,否则返回FALSE。
BiTreeDepth(T);
初始条件:二叉树T存在。
操作结果:返回T的深度。
Root(T);
初始条件:二叉树T的根存在。
操作结果:返回T的根。
Value(T,e);
初始条件:二叉树T存在,e是T中某个结点。
操作结果:返回e的值。
Assign(T,&e,value);
初始条件:二叉树T存在,e是T中的某个结点。
操作结果:结点e赋值为value。
Parent(T,e);
初始条件:二叉树T存在,e是T中的结点。
操作结果:若e是T的非根结点,则返回它的双亲,否则返回"空"。
LeftChild(T,e);
初始条件:二叉树T存在,e是T中的某个结点。
操作结果:返回e的左孩子。若e无左孩子,则返回"空"。
RightChild(T,e);
初始条件:二叉树T存在,e是T中的某个结点。
操作结果:返回e的右孩子。若e无右孩子,则返回"空"。
LeftSibling(T,e);
初始条件:二叉树T存在,e是T中的某个结点。
操作结果:返回e的左兄弟。若e是T的左孩子或无左兄弟,则返回"空"。
RightSibling(T,e);
初始条件:二叉树T存在,e是T中的某个结点。
操作结果:返回e的右兄弟。若e是T的右孩子或无右兄弟,则返回"空"。
InsertChild(T,p,LR,c);
初始条件:二叉树T存在,p指向T中的某个结点,LR为0或1,非空二叉树c与T不想交且右子树为空。
操作结果:根据LR为0或1,插入c为T中p所指结点的左或右子树。p所指结点的原有左或右子树则成为c的右子树。
DeleteChile(T,p,LR);
初始条件:二叉树T存在,p指向T中的某个结点,LR为0或1.
操作结果:根据LR为0或1,删除T中p所指结点的左或右子树。
PreOrderTraverse(T,visit());
初始条件:二叉树T存在,visit()是对结点操作的应用函数。
操作结果:先序遍历T,对每个结点调用函数visit一次且仅一次。一旦visit失败,则操作失败。
InOrderTraverse(T,visit());
初始条件:二叉树T存在,visit()是对结点操作的应用函数。
操作结果:中序遍历T,对每个结点调用函数visit一次且仅一次。一旦visit失败,则操作失败。
PostOrderTraverse(T,visit());
初始条件:二叉树T存在,visit()是对结点操作的应用函数。
操作结果:后序遍历T,对每个结点调用函数visit一次且仅一次。一旦visit失败,则操作失败。
LevelOrderTraverse(T,visit());
初始条件:二叉树T存在,visit()是对结点操作的应用函数。
操作结果:层序遍历T,对每个结点调用函数visit一次仅且一次。一旦visit失败,则操作失败。
}ADT BinaryTree
3.具体代码
- 二叉树的建立与遍历.h:
#include<stdio.h>
#include<stdlib.h>
#define elemtype char
#define OK 1
#define ERROR 0
typedef struct BiTNode{//二叉树
elemtype data;//数据
int deep;//深度
struct BiTNode *lchild;//左子树
struct BiTNode *rchild;//右子树
}*bitree,bitnode; //树结构
int createbitree(bitree *t,FILE *r,int n) //建树
{
char ch;//字符
if(fscanf(r,"%c",&ch) != EOF)//从文件中读取字符
{
if(ch == '\n')//如果换行
{
return OK;//则返回
}
if(ch == ' ')//如果读取为空格
{
(*t) = NULL;//则节点为空
return OK;
}
else//递归调用建立二叉树
{
(*t) = (bitree)malloc(sizeof(bitnode));//先对本节点创建空间
(*t)->data = ch;//数据
(*t)->deep = n+1;//深度,从1开始,不断往下加
createbitree(&((*t)->lchild),r,n+1);//对左子树开始递归
createbitree(&((*t)->rchild),r,n+1);//对右子树开始递归
}
return OK;
}
return ERROR;
}
void inorder(bitnode *t,void (*visit)(bitree t,FILE *w),FILE *w) //中序遍历
{
if(t == NULL)
{
return;
}
inorder(t->rchild,visit,w);//先打印右边的节点(因为在上方)
visit(t,w);//再中间节点
inorder(t->lchild,visit,w);//再左边节点
}
- 打印二叉树结构.c:
#include<stdio.h>
#include<stdlib.h>
#include"二叉树的建立与遍历.h"
void visit(bitree t,FILE *w) //打印二叉树
{
int i = 0;
for(;i < t->deep;i++)//按深度遍历
{
fprintf(w," ");//深度越长,打印的空格越多 (深度反映在水平方向)
}
fprintf(w,"%c",t->data);//把数据打印
fprintf(w,"\n\n\n");//空行
}
int main()
{
FILE *r,*w;//文件读写指针
printf("请将文件放在'二叉树数据.txt'中(放好按ENTER键继续):");
getchar();
if((r = fopen("二叉树数据.txt","rt")) == NULL)
{
exit(ERROR);
}
if((w = fopen("二叉树.txt","w")) == NULL)
{
printf("\n无法创建二叉树遍历结果.txt”!");
exit(ERROR);
}
int o=1;
for(;;o++)//循环
{
bitree t;//建立二叉树
if(createbitree(&t,r,0) == 0)//无法建立二叉树,退出循环
{
break;
}
if(createbitree(&t,r,0) == 1)//可以建立二叉树,就直接中序遍历输出
{
fprintf(w,"第%d个二叉树:\n\n\n",o);
inorder(t,visit,w);
fprintf(w,"\n\n\n");
}
}
fclose(w);
printf("结果已生成在'二叉树.txt'中。");
return 0;
}