Files
Data-Structure/Dev-C++/ExerciseBook/06.69/BiTree.cpp
T

221 lines
4.8 KiB
C++

/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#include "BiTree.h"
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* 初始化
*
* 构造空二叉树。
*/
Status InitBiTree(BiTree* T) {
if(T == NULL) {
return ERROR;
}
*T = NULL;
return OK;
}
/*
* 置空
*
* 清理二叉树中的数据,使其成为空树。
*/
Status ClearBiTree(BiTree* T) {
if(T == NULL) {
return ERROR;
}
// 在*T不为空时进行递归清理
if(*T) {
if((*T)->lchild!=NULL) {
ClearBiTree(&((*T)->lchild));
}
if((*T)->rchild!=NULL) {
ClearBiTree(&((*T)->rchild));
}
free(*T);
*T = NULL;
}
return OK;
}
/*
* ████████ 算法6.4 ████████
*
* 创建
*
* 按照预设的定义来创建二叉树。
* 这里约定使用【先序序列】来创建二叉树。
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateBiTree(BiTree* T, char* path) {
FILE* fp;
int readFromConsole; // 是否从控制台读取数据
// 如果没有文件路径信息,则从控制台读取输入
readFromConsole = path == NULL || strcmp(path, "") == 0;
if(readFromConsole) {
printf("请输入二叉树的先序序列,如果没有子结点,使用^代替:");
CreateTree(T, NULL);
} else {
// 打开文件,准备读取测试数据
fp = fopen(path, "r");
if(fp == NULL) {
return ERROR;
}
CreateTree(T, fp);
fclose(fp);
}
return OK;
}
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T) {
return T == NULL ? TRUE : FALSE;
}
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T) {
int LD, RD;
if(T == NULL) {
return 0; // 空树深度为0
} else {
LD = BiTreeDepth(T->lchild); // 求左子树深度
RD = BiTreeDepth(T->rchild); // 求右子树深度
return (LD >= RD ? LD : RD) + 1;
}
}
/*━━━━━━━━━━━━━━━━━━━━━━ 仅限内部使用的函数 ━━━━━━━━━━━━━━━━━━━━━━*/
// 创建二叉树的内部函数
static void CreateTree(BiTree* T, FILE* fp) {
char ch;
// 读取当前结点的值
if(fp == NULL) {
scanf("%c", &ch);
} else {
ReadData(fp, "%c", &ch);
}
if(ch == '^') {
*T = NULL;
} else {
// 生成根结点
*T = (BiTree) malloc(sizeof(BiTNode));
if(!(*T)) {
exit(OVERFLOW);
}
(*T)->data = ch;
CreateTree(&((*T)->lchild), fp); // 创建左子树
CreateTree(&((*T)->rchild), fp); // 创建右子树
}
}
/*━━━━━━━━━━━━━━━━━━━━━━ 图形化输出 ━━━━━━━━━━━━━━━━━━━━━━*/
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintTree(BiTree T) {
int level, width;
int i, j, k, w;
int begin;
int distance;
TElemType** tmp;
LinkQueue Q;
BiTree e;
// 遇到空树则无需继续计算
if(BiTreeEmpty(T)) {
printf("\n");
return;
}
level = BiTreeDepth(T); // (完全)二叉树结构高度
width = (int)pow(2, level)-1; // (完全)二叉树结构宽度
// 动态创建行
tmp = (TElemType**)malloc(level* sizeof(TElemType*));
// 动态创建列
for(i = 0; i < level; i++) {
tmp[i] = (TElemType*)malloc(width* sizeof(TElemType));
// 初始化内存值为空字符
memset(tmp[i], '\0', width);
}
// 借助队列实现层序遍历
InitQueue(&Q);
EnQueue(&Q, T);
// 遍历树中所有元素,将其安排到二维数组tmp中合适的位置
for(i = 0; i < level; i++) {
w = (int) pow(2, i); // 二叉树当前层的宽度
distance = width / w; // 二叉树当前层的元素间隔
begin = width / (int) pow(2, i + 1); // 二叉树当前层首个元素之前的空格数
for(k = 0; k < w; k++) {
DeQueue(&Q, &e);
if(e == NULL) {
EnQueue(&Q, NULL);
EnQueue(&Q, NULL);
} else {
j = begin + k * (1 + distance);
tmp[i][j] = e->data;
// 左孩子入队
EnQueue(&Q, e->lchild);
// 右孩子入队
EnQueue(&Q, e->rchild);
}
}
}
for(i = 0; i < level; i++) {
for(j = 0; j < width; j++) {
if(tmp[i][j] != '\0') {
printf("%c", tmp[i][j]);
} else {
printf(" ");
}
}
printf("\n");
}
}