开头先感谢朱洪老师的指导
准备工作一览
有了必要的工具后和框架后,需要仔细考虑二叉树创建的过程,将其转化为代码,写入修改好的框架中
1- 分析创建二叉树的具体过程

下面的部分参考代码,栈操作重复步骤就能得到先根序的二叉树

2- 由字符串创建先根序二叉树
bTree.h文件:
#ifndef _MEC_BINATRY_TREE_H_
#define _MEC_BINATRY_TREE_H_
typedef struct B_TREE {
int data;
struct B_TREE *left;
struct B_TREE *right;
}B_TREE;
//每个结点所必须的结构体
boolean createBTree(const char *str, B_TREE **root);
void destoryBTree(B_TREE **root);
void firstRootVisited(const B_TREE *root);
void middleRootVisited(const B_TREE *root);
void lastRootVisited(const B_TREE *root);
//定义创建,销毁,前中后根序遍历函数
#endif
bTree.c文件:
#include <stdio.h>
#include <malloc.h>
#include <ctype.h>
#include "mec.h"
#include "mecError.h"
#include "btree.h"
#include "stack.h"
extern const char *errMess;
//引用外部存储指针errMess
#define BTREE_STATUS_BEGIN 1
#define BTREE_STATUS_ROOT 2
#define BTREE_STATUS_SUB_TREE 3
#define BTREE_STATUS_DATA 4
#define BTREE_STATUS_COMMA 5
#define BTREE_STATUS_RIGHTBK 6
#define BTREE_STATUS_END 7
//为各种状态赋值
typedef struct BTREE_ARG {
int status; //当前状态
boolean ok; //是否成功处理
boolean finished; //是否处理结束
int index; //下标控制字符移动到下一个
boolean whichChild; //控制当前字母其左右孩子状态
B_TREE *root; //单独定义根节点指针
B_TREE *tmp; //暂存上一次处理的字母的状态
MEC_STACK *stack; //控制栈
}BTREE_ARG;
//每个字符在处理时需要的状态结构体
#define LEFT_CHILD 1
#define RIGHT_CHILD 2
//宏定义左右孩子
#define LEFT_BRACKET_TOO_MUCH -1
#define RIGHT_BRACKET_TOO_MUCH -2
//宏定义括号不匹配时两种情况
typedef void (*dealFun)(BTREE_ARG *arg, int ch);
//指向函数的指针
static void dealBTreeBegin(BTREE_ARG *arg, int ch);
static void dealBTreeRoot(BTREE_ARG *arg, int ch);
static void dealBTreeSubTree(BTREE_ARG *arg, int ch);
static void dealBTreeData(BTREE_ARG *arg, int ch);
static void dealBTreeComma(BTREE_ARG *arg, int ch);
static void dealBTreeRightBk(BTREE_ARG *arg, int ch);
static void dealBTreeEnd(BTREE_ARG *arg, int ch);
//定义一系列状态处理函数
static boolean isData(const int ch);
static void dealRoot(BTREE_ARG *arg, int ch);
static void dealLeftBracket(BTREE_ARG *arg);
static void dealRightBracket(BTREE_ARG *arg);
static void dealComma(BTREE_ARG *arg);
static void dealNode(BTREE_ARG *arg, int ch);
//定义一系列单个字符处理函数
static int getStackDeep(const char *str);
//定义一个获得栈深度的函数
栈容量获取函数:
static int getStackDeep(const char *str) {
int index;
int match = 0;
int maxMatch = 0;
//maxMatch是最多的左括号个数,同时也是子树最深的情况
//用maxMatch可以申请合理的栈容量
for (index = 0; match >= 0 && str[index]; index++) {
if ('(' == str[index]) {
++match;
maxMatch = maxMatch < match ? match : maxMatch;
//碰到左括号++match直到找到最大值
} else if (')' == str[index]) {
--match;
//遇到右括号,--match,若match最后为0,则括号匹配
//若match大于0,则左括号多余,match小于0,则右括号多余
if (match < 0) {
return RIGHT_BRACKET_TOO_MUCH;
}
}
}
return match == 0 ? maxMatch : LEFT_BRACKET_TOO_MUCH;
}
定义一系列字符处理函数,二叉树的主要生成过程就在其中,过程图在上面
static void dealNode(BTREE_ARG *arg, int ch) {
B_TREE *parent = NULL;
arg->tmp = (B_TREE *) calloc(sizeof(B_TREE), 1);
arg->tmp->data = ch;
parent = readTop(arg->stack);
if (LEFT_CHILD == arg->whichChild) {
parent->left = arg->tmp;
} else {
parent->right = arg->tmp;
}
arg->status = BTREE_STATUS_DATA;
arg->index++;
}
static void dealComma(BTREE_ARG *arg) {
B_TREE *parent = NULL;
parent = readTop(arg->stack);
if (parent->right != NULL) {
errMess = "二叉树不允许有超过2个节点";
arg->ok = FALSE;
return;
}
arg->whichChild = RIGHT_CHILD;
arg->status = BTREE_STATUS_COMMA;
arg->index++;
}
static void dealRightBracket(BTREE_ARG *arg) {
pop(arg->stack);
arg->status = BTREE_STATUS_RIGHTBK;
arg->index++;
}
static void dealLeftBracket(BTREE_ARG *arg) {
arg->whichChild = LEFT_CHILD;
push(arg->stack, arg->tmp);
arg->status = BTREE_STATUS_SUB_TREE;
arg->index++;
}
static void dealRoot(BTREE_ARG *arg, int ch) {
arg->root = (B_TREE *) calloc(sizeof(B_TREE), 1);
arg->root->data = ch;
arg->tmp = arg->root;
arg->status = BTREE_STATUS_ROOT;
arg->index++;
}
static boolean isData(const int ch) {
return isalnum(ch);
}
定义一系列状态处理函数,用来判断是否正确处理,是否结束处理,
且每次处理完单个字符,更改状态
const dealFun functions[] = {
NULL,
dealBTreeBegin,
dealBTreeRoot,
dealBTreeSubTree,
dealBTreeData,
dealBTreeComma,
dealBTreeRightBk,
dealBTreeEnd,
};
//使用指向函数的指针,可以方便的调用一系列处理状态的函数
static void dealBTreeEnd(BTREE_ARG *arg, int ch) {
arg->finished = TRUE;
}
//处理结束状态
static void dealBTreeRightBk(BTREE_ARG *arg, int ch) {
if (',' == ch) {
dealComma(arg);
} else if (')' == ch) {
dealRightBracket(arg);
} else {
arg->status = BTREE_STATUS_END;
}
}
//处理右括号状态
static void dealBTreeComma(BTREE_ARG *arg, int ch) {
if (')' == ch) {
dealRightBracket(arg);
} else if (isData(ch)) {
dealNode(arg, ch);
} else {
arg->ok = FALSE;
errMess = "此处希望出现\"数据\"或\")\"。";
}
}
//处理逗号状态
static void dealBTreeData(BTREE_ARG *arg, int ch) {
if ('(' == ch) {
dealLeftBracket(arg);
} else if (',' == ch) {
dealComma(arg);
} else if (')' == ch) {
dealRightBracket(arg);
} else {
arg->ok = FALSE;
errMess = "此处希望出现\")\"或\",\"。";
}
}
//处理数据状态
static void dealBTreeSubTree(BTREE_ARG *arg, int ch) {
if (isData(ch)) {
dealNode(arg, ch);
} else if (',' == ch) {
dealComma(arg);
} else {
arg->ok = FALSE;
errMess = "此处希望出现\"数据\"或\",\"。";
}
}
//处理子树状态
static void dealBTreeRoot(BTREE_ARG *arg, int ch) {
if ('(' == ch) {
dealLeftBracket(arg);
} else {
arg->status = BTREE_STATUS_END;
}
}
//处理根状态
static void dealBTreeBegin(BTREE_ARG *arg, int ch) {
if (isData(ch)) {
dealRoot(arg, ch);
} else {
arg->status = BTREE_STATUS_END;
}
}
//处理开始状态
真正开始创建二叉树的函数及销毁:
void destoryBTree(B_TREE **root) {
if (NULL == root) {
return;
}
destoryBTree(root->left);
destoryBTree(root->right);
free(root);
}
//销毁二叉树,这里使用了递归,通过不断的调用destoryBTree()函数自身,
//完成销毁左子树,销毁右子树,最后销毁根的功能,遇到NULL返回即可
boolean createBTree(const char *str, B_TREE **root) {
BTREE_ARG arg = {
BTREE_STATUS_BEGIN,
TRUE,
FALSE,
0,
LEFT_CHILD,
NULL,
NULL,
NULL,
};
int ch;
int stackCapacity;
if (NULL == str || NULL == root || NULL != *root) {
return FALSE;
}
stackCapacity = getStackDeep(str); //即maxMatch
if (stackCapacity < 0) {
arg.ok = FALSE;
errMess = LEFT_BRACKET_TOO_MUCH == stackCapacity
? "左括号失配"
: "右括号失配";
} else {
initStack(&arg.stack, stackCapacity);
}
//初始化栈
while (arg.ok && !arg.finished) {
arg.index += skipBlank(str + arg.index);
//跳过空格记录的下标
ch = str[arg.index];
functions[arg.status](&arg, ch); //指向函数的指针,根据arg.status
//灵活判断状态
}
destoryStack(&arg.stack);
//销毁栈
if (arg.ok) {
*root = arg.root;
} else {
destoryBTree(arg.root);
//哪怕是创建失败了,对于但是还有可能已经创建了残缺的树
//也需要销毁
}
return arg.ok;
}
二叉树的先中后根序遍历:
//同销毁,想要遍历二叉树,最快的方式就是递归
//递归某类结点直到处理完该类结点
//再进入下一类结点
//递归每次到底后返回上一层执行相应操作
void firstRootVisited(const B_TREE *root) {
if (NULL == root) {
return;
}
printf("%c ", root->data);
firstRootVisited(root->left);
firstRootVisited(root->right);
}
//先根序遍历
void middleRootVisited(const B_TREE *root) {
if (NULL == root) {
return;
}
middleRootVisited(root->left);
printf("%c ", root->data);
middleRootVisited(root->right);
}
//中根须遍历
void lastRootVisited(const B_TREE *root) {
if (NULL == root) {
return;
}
lastRootVisited(root->left);
lastRootVisited(root->right);
printf("%c ", root->data);
}
//后根序遍历
test.c创建:
#include <stdio.h>
#include "mec.h"
#include "mecError.h"
#include "btree.h"
int main(int argc, char const *argv[]) {
char str[1024] = {0};
B_TREE *root = NULL;
boolean ok = FALSE;
printf("输入二叉树表达式:");
gets(str);
ok = createBTree(str, &root);
if (!ok) {
showError();
return 1;
}
printf("先根序:\n");
firstRootVisited(root);
printf("\n");
printf("中根序:\n");
middleRootVisited(root);
printf("\n");
printf("后根序:\n");
lastRootVisited(root);
printf("\n");
return 0;
}
本文介绍了一种从字符串创建二叉树的方法,并实现了先根序、中根序和后根序遍历。通过定义特定的数据结构和状态机,文章详细解释了如何解析输入字符串,构建二叉树结构,并通过递归方式遍历树的不同部分。
5931

被折叠的 条评论
为什么被折叠?



