• 二叉树的遍历 详解及实现


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

    二叉树的遍历方式有三种:
    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;
    }
    

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

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

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

  • 相关阅读:
    二叉树中序遍历及后序遍历(下)
    完全二叉树和三序遍历算法(先序)(上)
    分布式调度——zookeeper
    Linux版JDK环境安装
    Redis的事务
    Redis的持久化——RDB与AOF
    分布式缓存——Redis
    非关系型数据库
    分布式存储——MySQL
    分布式系统
  • 原文地址:https://www.cnblogs.com/codderYouzg/p/12411946.html
Copyright © 2020-2023  润新知