二叉树的遍历 详解及实现

在之前的博文中我们讲解了二叉树的使用——《哈夫曼压缩》,那么,我们对于二叉树的操作不仅仅局限于创造,二叉树是一种储存处理方式,但是,我们不能仅仅是存储数据,那么,我们今天就来讲解一下从二叉树中读取数据的方法及操作。

二叉树的遍历方式有三种:
1.先根序:根 、左子树、右子树
2.中根序:左子树、根 、右孩子
3.后根序:左子树、右子树、根

现在通过一个例子来为,我让大家清晰了解们这三种遍历方法:
在这里插入图片描述

对于这个二叉树来说:
先根序遍历结果:A B D F G J C E H I
中根序遍历结果:F D J G B A H E I C
后根序遍历结果:F J G D B H I E C A

现在我们来构造一个二叉树,然后对这个二叉树进行遍历操作:
首先,我们按照我们之前博文中一直有的惯例,上手先编写"mec.h":

#ifndef _MEC_H_
#define _MEC_H_

typedef unsigned char boolean;
typedef boolean u8;

#define TRUE		1
#define FALSE		0

#define NOT_FOUND		-1

#define SET(v, i) (v |= (1 << ((i) ^ 7)))
#define CLR(v, i) (v &= ~(1 << ((i) ^ 7)))
#define	GET(v, i) (((v) & (1 << ((i) ^ 7))) != 0)

#endif

之后,我们再来构建二叉树“单节点”结构体

typedef struct BTREE {
	int data;
	struct BTREE *left;
	struct BTREE *right;
}BTREE;

那么,我们要构建二叉树,就要从键盘输入一个字符串,再读取字符串判断字符串输入是否合理,再根据正确的字符串构建二叉树
而这里通过字符串构建二叉树就要用到我们之前的博文——《表达式的处理》以及《哈夫曼压缩》两篇博文中的知识了。
现在我们来规定下输入字符串的正确格式如下:
A(B,C)
A(B,)
A(,B)
A(B)
A(,)
A()

那么,要实现通过输入的字符串构建二叉树,就要通过字符串来画状态变迁图
在这里插入图片描述那么,根据状态变迁图,我们来用宏定义所有可能出现的状态:

#define BTREE_STATUS_BEGIN		1
#define BTREE_STATUS_END		2
#define BTREE_STATUS_ROOT		3
#define BTREE_STATUS_LEFT		4
#define BTREE_STATUS_RIGHT		5
#define BTREE_STATUS_COMMA		6
#define BTREE_STATUS_CHILD		7

现在我们来构建一个表示完整二叉树的结构体:

typedef struct BTREE_ARG {
	int status;				//这个成员表示当前节点的状态
	int index;				//这个成员表示遍历字符串时用的下标
	boolean ok;				//这个成员表示遍历到当前位置字符串表达是否正确
	boolean finished;		//这个成员用来表示字符串是否遍历到末尾
	BTREE *root;			//这个成员用来存储第一个节点的信息
	BTREE *tmp;				//这个成员用来表示当前的节点的信息
	boolean whichChild;		//这个成员用来表示当前节点为父节点的“左孩子”还是“右孩子”
	MEC_STACK *nodeStack;	//这个成员用来存储父节点的首地址
	int breaketMatch;		//这个成员用来表示括号是否匹配
}BTREE_ARG;

现在来编写一个宏表示“左孩子”还是“右孩子”,以满足上面结构体内whichChild成员的赋值:

#define LEFT_CHILD		0
#define RIGHT_CHILD		1

因为我们读取的字符串可能出现错误,所以我们采用《表达式的处理》那一篇博客中的处理方式——编写“mecErr.c”和“mecErr.h”:
mecErr.h:

#ifndef _MEC_ERROR_H_
#define _MEC_ERROR_H_

void showError();

#endif

mecErr.c:

#include <stdio.h>

#include "mecError.h"

const char *errMess;	//这个变量在我们根据字符串构建二叉树中会用到

void showError() {
	if (NULL == errMess) {
		printf("No Error!
");
		return;
	}
	printf("Error:%s
", errMess);
}

我们再来思考一下,因为我们要在遍历字符串遇到新的有效节点时访问它的父节点,以便使父节点的孩子指针指向新节点,所以,我们用到了堆栈的处理方法,因为我们在之前的博文中已经进行过讲解,所以,这里就直接将代码复制过来:
mecStack.h:

#ifndef _MEC_STACK_H_
#define _MEC_STACK_H_

#include "mec.h"

typedef struct MEC_STACK {
	void **stack;
	int capacity;
	int top;
}MEC_STACK;

boolean initStack(MEC_STACK **stack, int capacity);	//初始化堆栈   函数
void destoryStack(MEC_STACK **stack);				//销毁堆栈     函数
boolean isStackEmpty(const MEC_STACK *stack);		//判栈空       函数
boolean isStackFull(const MEC_STACK *stack);		//判栈满       函数
boolean push(MEC_STACK *stack, void *data);			//将数据入栈   函数
void *pop(MEC_STACK *stack);						//将数据出栈   函数
void *readTop(const MEC_STACK *stack);				//读取栈顶指针 函数

#endif

mecStack.c:

#include <stdio.h>
#include <malloc.h>

#include "mec.h"
#include "mecStack.h"

void *readTop(const MEC_STACK *stack) {
	if (NULL == stack || isStackEmpty(stack)) {
		return NULL;
	}
	
	return stack->stack[stack->top - 1];
}

void *pop(MEC_STACK *stack) {
	if (NULL == stack || isStackEmpty(stack)) {
		return NULL;
	}
	
	return stack->stack[--stack->top];
}

boolean push(MEC_STACK *stack, void *data) {
	if (NULL == stack || isStackFull(stack)) {
		return FALSE;
	}
	stack->stack[stack->top++] = data;
	
	return TRUE;
}

boolean isStackFull(const MEC_STACK *stack) {
	return stack != NULL && stack->top >= stack->capacity;
}

boolean isStackEmpty(const MEC_STACK *stack) {
	return stack != NULL && stack->top <= 0;
}

void destoryStack(MEC_STACK **stack) {
	if (NULL == stack || NULL == *stack) {
		return;
	}
	
	free((*stack)->stack);
	free(*stack);
	
	*stack = NULL;
}

boolean initStack(MEC_STACK **stack, int capacity) {
	MEC_STACK *res;
	
	if (NULL == stack || NULL != *stack || capacity <= 0) {
		return FALSE;
	}
	
	res = (MEC_STACK *) calloc(sizeof(MEC_STACK), 1);
	res->stack = (void **) calloc(sizeof(void *), capacity);
	res->capacity = capacity;
	res->top = 0;
	
	*stack = res;
	
	return TRUE;
}

那么,大体我们都准备好了,我们现在来编写根据字符串构建二叉树的函数

boolean createBTreeByString(const char *str, BTREE **btree) {
	BTREE_ARG arg = {
		BTREE_STATUS_BEGIN, // int status;
		0,					// int index;
		TRUE,				// boolean ok;
		FALSE,				// boolean finished;
		NULL,				// BTREE *root;
		NULL,				// BTREE *tmp;
		LEFT_CHILD,			// boolean whichChild;
		NULL,				// MEC_STACK *nodeStack;
		0,					// int breaketMatch;
	};

	if (NULL == btree || NULL != *btree) {
		return FALSE;
	}

	initStack(&arg.nodeStack, strlen(str));					//这个初始化堆栈函数在上面编写的"mecStack.h"文件中声明

	while (arg.ok && !arg.finished) {
		arg.index += skipBlank(str + arg.index);			//跳过字符串中空格函数,我们在下面内容中进行编写
		if (BTREE_STATUS_BEGIN == arg.status) {
			dealBtreeStatusBegin(str[arg.index], &arg);		//处理开始状态函数,我们在下面内容中进行编写
		} else if (BTREE_STATUS_END == arg.status) {
			dealBtreeStatusEnd(&arg, btree);				//处理结束状态函数,我们在下面内容中进行编写
		} else if (BTREE_STATUS_LEFT == arg.status) {
			dealBtreeStatusLeft(str[arg.index], &arg);		//处理左括号状态函数,我们在下面内容中进行编写
		} else if (BTREE_STATUS_ROOT == arg.status) {
			dealBtreeStatusRoot(str[arg.index], &arg);		//处理根节点状态函数,我们在下面内容中进行编写
		} else if (BTREE_STATUS_COMMA == arg.status) {
			dealBtreeStatusComma(str[arg.index], &arg);		//处理小数点状态函数,我们在下面内容中进行编写
		} else if (BTREE_STATUS_CHILD == arg.status) {
			dealBtreeStatusChild(str[arg.index], &arg);		//处理孩子状态函数,我们在下面内容中进行编写
		} else if (BTREE_STATUS_RIGHT == arg.status) {
			dealBtreeStatusRight(str[arg.index], &arg);		//处理右括号状态函数,我们在下面内容中进行编写
		}
	}

	if (FALSE == arg.ok) {		// 要销毁生成了一半的二叉树中的节点!这就牵扯到二叉树的遍历了(这篇博文通过“后根序”方式实现)
		destroyBtree(arg.root);
		arg.root = NULL;
	}
	destoryStack(&arg.nodeStack);							//销毁堆栈函数,在上面编写的"mecStack.h"文件中声明

	return arg.ok;
}

那么,我们现在来编写处理各种状态的函数:
1.处理开始状态的函数:

void dealBtreeStatusBegin(int ch, BTREE_ARG *arg) {
	if (isalpha(ch)) {
		arg->root = arg->tmp = createOneNode(ch);
		++arg->index;
		arg->status = BTREE_STATUS_ROOT;
	} else {
		errMess = "出师未捷身先死";
		arg->ok = FALSE;
	}
}

2.处理结束状态函数:

void dealBtreeStatusEnd(BTREE_ARG *arg, BTREE **root) {
	if (arg->breaketMatch != 0) {						//因为我们等会遇到左括号会使这个变量加1,遇到右括号使这个变量减1,所以在结束时应该为0,而在我们处理右括号时会解决左括号缺失的问题,所以,这里只会是因为缺右括号
		errMess = "括号不匹配之缺少右括号";
		arg->ok = FALSE;
		return;
	}
	*root = arg->root;									//这里的赋值是为了等会在主函数中销毁整个二叉树
	arg->finished = TRUE;
}

3.处理左括号状态函数:

void dealBtreeStatusLeft(int ch, BTREE_ARG *arg) {
	if (isalpha(ch)) {
		processAlpha(ch, arg);							//处理字母函数,在之后代码中编写
	} else if (',' == ch) {
		processComma(arg);								//处理逗号函数,在之后代码中编写
	} else if (')' == ch) {
		processRightBracket(arg);						//处理右括号函数,在之后代码中编写
	} else {
		errMess ="非法字符!"
		arg->ok = FALSE;
	}
}

3.1.处理字母函数:

void processAlpha(int ch, BTREE_ARG *arg) {
	BTREE *parent;

	parent = (BTREE *) readTop(arg->nodeStack);
	if (arg->whichChild == RIGHT_CHILD && parent->right != NULL) {
		errMess = "孩子个数不满足要求!";
		arg->ok = FALSE;
		return;
	}
	
	arg->tmp = createOneNode(ch);					//创造新节点函数,在之后代码中编写
	if (LEFT_CHILD == arg->whichChild) {
		parent->left = arg->tmp;
	} else {
		parent->right = arg->tmp;
	}
	++arg->index;
	arg->status = BTREE_STATUS_CHILD;
}

3.1.1.创造新节点函数:

BTREE *createOneNode(int ch) {
	BTREE *res = calloc(sizeof(BTREE), 1);
	res->data = ch;
	res->left = res->right = NULL;

	return res;
}

3.2.处理逗号函数:

void processComma(BTREE_ARG *arg) {
	arg->whichChild = RIGHT_CHILD;
	++arg->index;
	arg->status = BTREE_STATUS_COMMA;
}

3.3.处理右括号函数:

void processRightBracket(BTREE_ARG *arg) {
	if (--arg->breaketMatch < 0) {
		errMess = "括号不匹配之缺少左括号!";				
		arg->ok = FALSE;
		return;
	}

	pop(arg->nodeStack);
	++arg->index;
	arg->status = BTREE_STATUS_RIGHT;
}

4.处理根节点状态函数:

void dealBtreeStatusRoot(int ch, BTREE_ARG *arg) {
	if ('(' == ch) {
		processLeftBracket(arg);				//处理左括号函数,在之后代码中编写
	} else if (0 == ch) {
		arg->status = BTREE_STATUS_END;
	} else {
		errMess = "非法字符!";
		arg->ok = FALSE;
	}
}

4.1.处理左括号函数:

void processLeftBracket(BTREE_ARG *arg) {
	arg->breaketMatch++;
	push(arg->nodeStack, arg->tmp);
	arg->whichChild = LEFT_CHILD;
	++arg->index;
	arg->status = BTREE_STATUS_LEFT;
}

5.处理小数点状态函数:

void dealBtreeStatusComma(int ch, BTREE_ARG *arg) {
	if (isalpha(ch)) {
		processAlpha(ch, arg);
	} else if (')' == ch) {
		processRightBracket(arg);
	} else {
		errMess = "非法字符!";
		arg->ok = FALSE;
	}
}

6.处理孩子状态函数:

void dealBtreeStatusChild(int ch, BTREE_ARG *arg) {
	if ('(' == ch) {
		processLeftBracket(arg);
	} else if (')' == ch) {
		processRightBracket(arg);
	} else if (',' == ch) {
		processComma(arg);
	} else {
		errMess = "非法字符!";
		arg->ok = FALSE;
	}
}

7.处理右括号状态函数:

void dealBtreeStatusRight(int ch, BTREE_ARG *arg) {
	if (',' == ch) {
		processComma(arg);
	} else if (')' == ch) {
		processRightBracket(arg);
	} else if (0 == ch) {
		arg->status = BTREE_STATUS_END;
	} else {
		errMess = "非法字符!";
		arg->ok = FALSE;
	}
}

8.跳过字符串中空格函数:

int skipBlank(const char *str) {
	int index;

	for (index = 0; str[index] && isspace(str[index]); index++) {
		;
	}

	return index;
}

那么,到目前位置,我们通过字符串构建二叉树的操作已经基本完成了,因为我们接下来的销毁不完整二叉树(字符串中间错误,构造了一半二叉树)和展示二叉树各节点储存的数值,就需要我们遍历二叉树,那么,现在我们来编写今天的主要讲解的内容——二叉树的遍历问题:

在上面我们将结果二叉树的遍历一共右三种最基本的形式:
先根序、中根序、后根序
那么,在编写展示二叉树各节点存储的信息时,我们将这三种方法都来实现一遍:
1.(先根序版)展示函数

void travelFirstRoot(const BTREE *root) {
	if (NULL == root) {
		return;
	}
	printf("%c ", root->data);
	travelFirstRoot(root->left);
	travelFirstRoot(root->right);
}

2.(中根序版)展示函数

void travelMiddleRoot(const BTREE *root) {
	if (NULL == root) {
		return;
	}
	travelMiddleRoot(root->left);
	printf("%c ", root->data);
	travelMiddleRoot(root->right);
}

3.(后根序版)展示函数

void travelLastRoot(const BTREE *root) {
	if (NULL == root) {
		return;
	}
	travelLastRoot(root->left);
	travelLastRoot(root->right);
	printf("%c ", root->data);
}

以上的递归,可能有的同学觉得看不明白,这就需要同学们自己动手来跟着代码实现一遍,这样,就会更深一步理解这里递归函数的妙处了。

那么,在完成了一切操作之后,我们一定要记得销毁二叉树,否则会造成“内存泄漏”,浪费计算机内存!
现在来编写销毁二叉树函数:

void destroyBtree(BTREE *root) {
	if (NULL == root) {					//当根节点首地址为NULL时,则在上一次递归中完成了对叶子节点的释放(对于叶子节点知识不清楚的,请观看本人博文——《哈夫曼压缩》)
		return;
	}
	destroyBtree(root->left);
	destroyBtree(root->right);
	free(root);
}

那么,现在我们来总结一下我们今天所编写的工具函数:
btree.h:

#ifndef _MEC_B_TREE_H_
#define _MEC_B_TREE_H_

#include "mec.h"

typedef struct BTREE {
	int data;
	struct BTREE *left;
	struct BTREE *right;
}BTREE;

#define BTREE_STATUS_BEGIN		1
#define BTREE_STATUS_END		2
#define BTREE_STATUS_ROOT		3
#define BTREE_STATUS_LEFT		4
#define BTREE_STATUS_RIGHT		5
#define BTREE_STATUS_COMMA		6
#define BTREE_STATUS_CHILD		7

boolean createBTreeByString(const char *str, BTREE **btree);
void travelFirstRoot(const BTREE *root);
void travelMiddleRoot(const BTREE *root);
void travelLastRoot(const BTREE *root);
void destroyBtree(BTREE *root);

#endif

btree.c:

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>

#include "mec.h"
#include "btree.h"
#include "mecStack.h"
#include "mecError.h"

void destroyBtree(BTREE *root) {
	if (NULL == root) {
		return;
	}
	destroyBtree(root->left);
	destroyBtree(root->right);
	free(root);
}

void travelLastRoot(const BTREE *root) {
	if (NULL == root) {
		return;
	}
	travelLastRoot(root->left);
	travelLastRoot(root->right);
	printf("%c ", root->data);
}

void travelMiddleRoot(const BTREE *root) {
	if (NULL == root) {
		return;
	}
	travelMiddleRoot(root->left);
	printf("%c ", root->data);
	travelMiddleRoot(root->right);
}

void travelFirstRoot(const BTREE *root) {
	if (NULL == root) {
		return;
	}
	printf("%c ", root->data);
	travelFirstRoot(root->left);
	travelFirstRoot(root->right);
}

typedef struct BTREE_ARG {
	int status;
	int index;
	boolean ok;
	boolean finished;
	BTREE *root;
	BTREE *tmp;
	boolean whichChild;
	MEC_STACK *nodeStack;
	int breaketMatch;
}BTREE_ARG;

#define LEFT_CHILD		0
#define RIGHT_CHILD		1

extern const char *errMess;			//这里extern表示是外部文件变量

static int skipBlank(const char *str);
static void dealBtreeStatusBegin(int ch, BTREE_ARG *arg);
static void dealBtreeStatusEnd(BTREE_ARG *arg, BTREE **root);
static void dealBtreeStatusLeft(int ch, BTREE_ARG *arg);
static void dealBtreeStatusRoot(int ch, BTREE_ARG *arg);
static void dealBtreeStatusComma(int ch, BTREE_ARG *arg);
static void dealBtreeStatusChild(int ch, BTREE_ARG *arg);
static void dealBtreeStatusRight(int ch, BTREE_ARG *arg);
static BTREE *createOneNode(int ch);
static void processAlpha(int ch, BTREE_ARG *arg);
static void processLeftBracket(BTREE_ARG *arg);
static void processRightBracket(BTREE_ARG *arg);
static void processComma(BTREE_ARG *arg);

static void processComma(BTREE_ARG *arg) {
	arg->whichChild = RIGHT_CHILD;
	++arg->index;
	arg->status = BTREE_STATUS_COMMA;
}

static void processRightBracket(BTREE_ARG *arg) {
	if (--arg->breaketMatch < 0) {
		errMess = "括号不匹配之缺少左括号!";
		arg->ok = FALSE;
		return;
	}

	pop(arg->nodeStack);
	++arg->index;
	arg->status = BTREE_STATUS_RIGHT;
}

static void processLeftBracket(BTREE_ARG *arg) {
	arg->breaketMatch++;
	push(arg->nodeStack, arg->tmp);
	arg->whichChild = LEFT_CHILD;
	++arg->index;
	arg->status = BTREE_STATUS_LEFT;
}

static void processAlpha(int ch, BTREE_ARG *arg) {
	BTREE *parent;

	parent = (BTREE *) readTop(arg->nodeStack);
	if (arg->whichChild == RIGHT_CHILD && parent->right != NULL) {
		errMess = "孩子个数不满足要求!";
		arg->ok = FALSE;
		return;
	}
	
	arg->tmp = createOneNode(ch);
	if (LEFT_CHILD == arg->whichChild) {
		parent->left = arg->tmp;
	} else {
		parent->right = arg->tmp;
	}
	++arg->index;
	arg->status = BTREE_STATUS_CHILD;
}

static BTREE *createOneNode(int ch) {
	BTREE *res = calloc(sizeof(BTREE), 1);
	res->data = ch;
	res->left = res->right = NULL;

	return res;
}

static void dealBtreeStatusRight(int ch, BTREE_ARG *arg) {
	if (',' == ch) {
		processComma(arg);
	} else if (')' == ch) {
		processRightBracket(arg);
	} else if (0 == ch) {
		arg->status = BTREE_STATUS_END;
	} else {
		errMess = "非法字符!";
		arg->ok = FALSE;
	}
}

static void dealBtreeStatusChild(int ch, BTREE_ARG *arg) {
	if ('(' == ch) {
		processLeftBracket(arg);
	} else if (')' == ch) {
		processRightBracket(arg);
	} else if (',' == ch) {
		processComma(arg);
	} else {
		errMess = "非法字符!";
		arg->ok = FALSE;
	}
}

static void dealBtreeStatusComma(int ch, BTREE_ARG *arg) {
	if (isalpha(ch)) {
		processAlpha(ch, arg);
	} else if (')' == ch) {
		processRightBracket(arg);
	} else {
		errMess = "非法字符!";
		arg->ok = FALSE;
	}
}

static void dealBtreeStatusRoot(int ch, BTREE_ARG *arg) {
	if ('(' == ch) {
		processLeftBracket(arg);
	} else if (0 == ch) {
		arg->status = BTREE_STATUS_END;
	} else {
		errMess = "非法字符!";
		arg->ok = FALSE;
	}
}

static void dealBtreeStatusLeft(int ch, BTREE_ARG *arg) {
	if (isalpha(ch)) {
		processAlpha(ch, arg);
	} else if (',' == ch) {
		processComma(arg);
	} else if (')' == ch) {
		processRightBracket(arg);
	} else {
		errMess = "非法字符!";
		arg->ok = FALSE;
	}
}

static void dealBtreeStatusEnd(BTREE_ARG *arg, BTREE **root) {
	if (arg->breaketMatch != 0) {
		errMess = "括号不匹配之缺少右括号";
		arg->ok = FALSE;
		return;
	}
	*root = arg->root;
	arg->finished = TRUE;
}

static void dealBtreeStatusBegin(int ch, BTREE_ARG *arg) {
	if (isalpha(ch)) {
		arg->root = arg->tmp = createOneNode(ch);
		++arg->index;
		arg->status = BTREE_STATUS_ROOT;
	} else {
		errMess = "出师未捷身先死!";
		arg->ok = FALSE;
	}
}

boolean createBTreeByString(const char *str, BTREE **btree) {
	BTREE_ARG arg = {
		BTREE_STATUS_BEGIN, // int status;
		0,					// int index;
		TRUE,				// boolean ok;
		FALSE,				// boolean finished;
		NULL,				// BTREE *root;
		NULL,				// BTREE *tmp;
		LEFT_CHILD,			// boolean whichChild;
		NULL,				// MEC_STACK *nodeStack;
		0,					// int breaketMatch;
	};

	if (NULL == btree || NULL != *btree) {
		return FALSE;
	}

	initStack(&arg.nodeStack, strlen(str));

	while (arg.ok && !arg.finished) {
		arg.index += skipBlank(str + arg.index);
		if (BTREE_STATUS_BEGIN == arg.status) {
			dealBtreeStatusBegin(str[arg.index], &arg);
		} else if (BTREE_STATUS_END == arg.status) {
			dealBtreeStatusEnd(&arg, btree);
		} else if (BTREE_STATUS_LEFT == arg.status) {
			dealBtreeStatusLeft(str[arg.index], &arg);
		} else if (BTREE_STATUS_ROOT == arg.status) {
			dealBtreeStatusRoot(str[arg.index], &arg);
		} else if (BTREE_STATUS_COMMA == arg.status) {
			dealBtreeStatusComma(str[arg.index], &arg);
		} else if (BTREE_STATUS_CHILD == arg.status) {
			dealBtreeStatusChild(str[arg.index], &arg);
		} else if (BTREE_STATUS_RIGHT == arg.status) {
			dealBtreeStatusRight(str[arg.index], &arg);
		}
	}

	if (FALSE == arg.ok) {				// 要销毁生成了一半的二叉树中的节点!
		destroyBtree(arg.root);
		arg.root = NULL;
	}
	destoryStack(&arg.nodeStack);

	return arg.ok;
}

static int skipBlank(const char *str) {
	int index;

	for (index = 0; str[index] && isspace(str[index]); index++) {
		;
	}

	return index;
}

这里对上面函数的放置和声明做一些解释,因为我们提供的函数只是.h文件中那5个,剩下我们编写的函数都是为了辅助那5个函数编写而编写的,并且我们不希望那些函数被用户使用,所以我们将那些函数的声明放在了.c文件中,并且在那些函数的声明以及编写时在前面加上static修饰,表示仅在该文件中能够被使用。

作为数据结构与算法的最后几篇博文,希望能在这个时候让大家明白我们所编写的工具函数所在的.以及.h文件该怎样规划。

那么,工具函数文件我们都已经准备妥当了,现在来编写一个.c文件来调用这些工具函数来展示下使用方法吧:
demoBtree.c

#include <stdio.h>

#include "mec.h"
#include "mecError.h"
#include "btree.h"

int main() {
	BTREE *root = NULL;
	char str[80];
	boolean ok;

	printf("请输入二叉树字符串:");
	gets(str);

	ok = createBTreeByString(str, &root);
	if (FALSE == ok) {
		showError();

		return -1;
	}
	printf("先根序遍历结果:
");
	travelFirstRoot(root);
	printf("
中根序遍历结果:
");
	travelMiddleRoot(root);
	printf("
后根序遍历结果:
");
	travelLastRoot(root);
	printf("
");

	destroyBtree(root);
	root = NULL;					//完全用完的指针赋值为NULL是一个好习惯,这点在今后的学习中会体现到

	return 0;
}

这次的代码还是需要通过命令行窗口或者虚拟机进行多文件联编,才能实现。
而且这次的代码与以往勾连过深,希望观看或者学习本篇博文的同学能够耐下性子先观看本人《堆栈的实现》以及《表达式的处理》两篇博文

《堆栈的实现》
《表达式的处理》

那么,这一节的知识就到此为止了,希望同学们对于二叉树的理解能更深一步。

原文地址:https://www.cnblogs.com/codderYouzg/p/12411946.html