第一:写自己的头文件”BTree.h“
#ifndef _B_TREE_H_
#define _B_TREE_H_
#define LEFT_CHILD 1 //左孩子
#define RIGHT_CHILD 2 //右孩子
typedef struct BTREE{
NODE_TYPE value;
struct BTREE *leftChild;
struct BTREE *rightChild;
}BTREE;
#endif
第二: 通过字符串 a(b,c)输入二叉树
首先我们将录入的字符串分为以下六种状态:
//定义字符串的六种状态
#define BTREE_STATUS_BEGIN 1 //开始
#define BTREE_STATUS_END 2 //结束
#define BTREE_STATUS_ALPHA 3 //字符
#define BTREE_STATUS_LEFT_BRACKET 4 //左括号
#define BTREE_STATUS_RIGHT_BRACKET 5 //右括号
#define BTREE_STATUS_COMMA 6 //逗号
#define BTREE_STATUS_BEGIN 1 //开始
#define BTREE_STATUS_END 2 //结束
#define BTREE_STATUS_ALPHA 3 //字符
#define BTREE_STATUS_LEFT_BRACKET 4 //左括号
#define BTREE_STATUS_RIGHT_BRACKET 5 //右括号
#define BTREE_STATUS_COMMA 6 //逗号
刚开始为开始状态,然后根据状态进行转换。
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include"MecTool.h"
typedef char NODE_TYPE;
#include"BTree.h"
typedef BTREE *USER_TYPE;
#include"MecStack.h"
//定义字符串的六种状态
#define BTREE_STATUS_BEGIN 1 //开始
#define BTREE_STATUS_END 2 //结束
#define BTREE_STATUS_ALPHA 3 //字符
#define BTREE_STATUS_LEFT_BRACKET 4 //左括号
#define BTREE_STATUS_RIGHT_BRACKET 5 //右括号
#define BTREE_STATUS_COMMA 6 //逗号
//将需要用到的变量封装起来
typedef struct{
int status; //状态
boolean Ok; //是否正确
boolean finished; //是否
int index; //处理的字符位置
int whichChild; //处理的哪一个孩子;
BTREE *root; //指向的二叉树
BTREE *node; //指向新生成的节点
MEC_STACK *nodePointStack; //指向栈
}BTREE_PARA;
boolean processBtreeComma(char ch, BTREE_PARA *para)
{
if(isalpha(ch)){
dealAlpha(ch, para);
para->index++;
para->status = BTREE_STATUS_ALPHA;
}else if(')' == ch){
dealRightBracket(para);
para->index++;
para->status = BTREE_STATUS_RIGHT_BRACKET;
}else{
para->Ok = FALSE;
}
return para->Ok;
}
boolean processBtreeRightBracket(char ch, BTREE_PARA *para)
{
if(',' == ch){
dealComma(para);
para->index++;
para->status = BTREE_STATUS_COMMA;
}else if(')' == ch){
if(FALSE == dealRightBracket(para)){
return para->Ok;
}
para->index++;
para->status = BTREE_STATUS_RIGHT_BRACKET;
printf("zheli:%d\n",para->Ok);
}else if(0 == ch){
para->status = BTREE_STATUS_END;
}else
printf("输出错误!\n");
return para->Ok;
}
boolean processBtreeLeftBracket(char ch, BTREE_PARA *para)
{
if(isalpha(ch)){
dealAlpha(ch, para);
para->index++;
para->status = BTREE_STATUS_ALPHA;
}else if(',' == ch){
dealComma(para);
para->index++;
para->status = BTREE_STATUS_COMMA;
}else
printf("输出错误!\n");
return para->Ok;
}
/*
字符状态表示我已经处理完了这个字符,看看需要变成什么状态
*/
boolean processBtreeAlpha(char ch, BTREE_PARA *para)
{
if('(' == ch){
if(FALSE ==dealLeftBracket(para)){
return para->Ok;
}
para->index++;
para->status = BTREE_STATUS_LEFT_BRACKET;
}else if(')' == ch){
dealRightBracket(para);
para->index++;
para->status = BTREE_STATUS_RIGHT_BRACKET;
}else if(',' == ch){
dealComma(para);
para->index++;
para->status = BTREE_STATUS_COMMA;
}else if(0 == ch){
para->status = BTREE_STATUS_END;
}else{
printf("输出错误!\n");
para->Ok = FALSE;
}
return para->Ok;
}
boolean processBtreeEnd(BTREE **pMainRoot, BTREE_PARA *para)
{
*pMainRoot = para->root;//就是bt指向的空间 == para->root
para->finished = TRUE;
return para->Ok;
}
boolean processBtreeBegin(char ch, BTREE_PARA *para)
{
//判断是不是一个字母
if(isalpha(ch)){
dealAlpha(ch, para);
para->index++;//指向下一个字符
para->status = BTREE_STATUS_ALPHA;//变成字符状态
}else{
printf("输入的字符有问题");
return FALSE;
}
return para->Ok;
}
boolean createBtreeByString(char *str, BTREE **bt)
{
BTREE_PARA para ={
BTREE_STATUS_BEGIN,
TRUE,
FALSE,
0,
LEFT_CHILD,
*bt,
NULL,
NULL,
};
if(para.root != NULL){
printf("二叉树存在");
return FALSE;
}
//初始化栈,需要两个参数,一个是指向栈的指针的地址值,还有申请空间。
initMecStack(¶.nodePointStack, strlen(str) / 2);
//分状态处理字符串
while(para.Ok && !para.finished){
para.index = skipBlank(str, para.index); //跳过空白
if(BTREE_STATUS_BEGIN == para.status){
processBtreeBegin(str[para.index], ¶);
}else if(BTREE_STATUS_END == para.status){
processBtreeEnd(bt, ¶);
}else if(BTREE_STATUS_ALPHA == para.status){
processBtreeAlpha(str[para.index], ¶);
}else if(BTREE_STATUS_LEFT_BRACKET == para.status){
processBtreeLeftBracket(str[para.index], ¶);
}else if(BTREE_STATUS_RIGHT_BRACKET == para.status){
processBtreeRightBracket(str[para.index], ¶);
}else if(BTREE_STATUS_COMMA == para.status){
processBtreeComma(str[para.index], ¶);
}
}
return para.Ok;
}
void main()
{
char str[80] = {0};
BTREE *btree = NULL;
BTREE *btreeCopy = NULL;
int depth = 0;
int count = 0;
printf("请输入一个二叉树A(B,C):");
gets(str);
if(TRUE == createBtreeByString(str, &btree))
printf("表达式正常!\n");
printf("先序遍历是");
showFirstTree(btree);
printf("\n");
printf("中序遍历是");
showMiddleTree(btree);
printf("\n");
printf("后序遍历是");
showAfterTree(btree);
printf("\n");
depth = getTreeDepth(btree);
printf("树的深度是:%d", depth);
printf("\n");
getTreeCount(btree, &count);
printf("树的叶子节点个数是:%d", count);
printf("\n");
btreeCopy = copyTree(btree);
printf("先序遍历是");
showFirstTree(btreeCopy);
}
处理字符:将字符存储起来,通过读取栈顶元素将其链接它的双亲节点上。
boolean dealAlpha(char ch, BTREE_PARA *para)
{
BTREE *parent = NULL;//存放栈顶元素
para->node = (BTREE *)calloc(sizeof(BTREE), 1);
para->node->value = ch;
if(NULL == para->root)//是第一个节点
{
para->root = para->node;
}else{
if(readTop(*para->nodePointStack, &parent) == FALSE){
printf("读取栈顶元素失败");
para->Ok = FALSE;
return para->Ok;
}
if(LEFT_CHILD == para->whichChild){
parent->leftChild = para->node;
}else{
parent->rightChild = para->node;
}
}
return para->Ok;
}
处理右括号,只需要将根节点出栈即可(栈中存储的都是有孩子且没有输入的节点)
boolean dealRightBracket(BTREE_PARA *para)
{
BTREE* value;
pop(para->nodePointStack, &value);//根节点出栈
return para->Ok;
}
处理左括号,碰见左括号证明左括号前面的字符是一个双亲节点且子节点没有录入,要把这个字符入栈。
boolean dealLeftBracket(BTREE_PARA *para)
{
//根节点入栈
push(para->nodePointStack,para->node);
//下一个字母是左子树
para->whichChild = LEFT_CHILD;
return para->Ok;
}
处理逗号,都要证明下一个字符是右孩子
boolean dealComma(BTREE_PARA *para)
{
//下一个将要连接右孩子
para->whichChild = RIGHT_CHILD;
return para->Ok;
}
上面的函数可以实现从键盘输入类似于A(B,C)的字符创建二叉树的功能
二叉树的常见遍历操作
1 遍历操作:
每个节点都会被左三次,此时不同的就是输出时刻。
先序遍历:根节点先输出
void showFirstTree(BTREE *root) { if(root == NULL) return; printf("%c \t", root->value); showFirstTree(root->leftChild); showFirstTree(root->rightChild);
中序遍历:根节点先输出
void showMiddleTree(BTREE *root)
{
if(root == NULL)
return;
showMiddleTree(root->leftChild);
printf("%c \t", root->value);
showMiddleTree(root->rightChild);
}
后序遍历:根节点最后输出
void showAfterTree(BTREE *root)
{
if(root == NULL)
return;
showAfterTree(root->leftChild);
showAfterTree(root->rightChild);
printf("%c \t", root->value);
}
}
2 求二叉树的深度
二叉树的深度 等于左子树和右子树其中较大的一个加上1
使用递归
int getTreeDepth(BTREE *root)
{
int depth = 0;
int depthLeft = 0;
int depthRight = 0;
if(root == NULL){
return depth;//叶子节点,它的高度是0
}else{
depthLeft = getTreeDepth(root->leftChild);//得到非叶子节点左子树高度
depthRight = getTreeDepth(root->rightChild);//得到非叶子节点右子树高度
depth = ((depthLeft > depthRight)? depthLeft :depthRight) + 1;
}
return depth;
}
3 复制一个二叉树
BTREE* copyTree(BTREE *root)
{
BTREE *p = NULL;//指向这个将要生成的节点
BTREE *leftLink = NULL;//指向将要生成节点的左孩子
BTREE *rightLink = NULL;//右孩子
if(root == NULL)
return;
if(root->leftChild != NULL)//这个要复制的节点的左孩子不是空
{
leftLink = copyTree(root->leftChild);//复制这个左孩子
}else
leftLink = NULL;
if(root->rightChild != NULL)//这个要复制的节点的左孩子不是空
{
rightLink = copyTree(root->rightChild);//复制这个左孩子
}else
rightLink = NULL;
//为新生成的节点申请空间
if((p = (BTREE *)calloc(sizeof(BTREE), 1)) == NULL){
printf("申请空间失败");
}
p->leftChild = leftLink;
p->rightChild = rightLink;
p->value = root->value;
return p;
}
3 求叶子节点数
void getTreeCount(BTREE *root, int *pcount)
{
if(root == NULL){
return;
}
if(root->leftChild == NULL && root->rightChild == NULL){
(*pcount)++;
}//叶子节点的左孩子和右孩子都是空
getTreeCount(root->leftChild, pcount);
getTreeCount(root->rightChild, pcount);
}