创建二叉树及二叉树三种遍历(下)

本文介绍了一种从字符串创建二叉树的方法,并实现了先根序、中根序和后根序遍历。通过定义特定的数据结构和状态机,文章详细解释了如何解析输入字符串,构建二叉树结构,并通过递归方式遍历树的不同部分。
摘要由CSDN通过智能技术生成
开头先感谢朱洪老师的指导

准备工作一览

有了必要的工具后和框架后,需要仔细考虑二叉树创建的过程,将其转化为代码,写入修改好的框架中

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值