如“a b + c d e + * *”生成表达式树的主要过程如下图所示:
(1)依次读入操作数a 和 b,并压入栈中
(2)遇到操作符“+”
(4)遇到“+”操作符
(5)遇到“*”操作符
(6)遇到“*”操作符
/* 表达式二叉树 */
//#include "stdafx.h"
//博客地址:https://blog.csdn.net/y_16041527
#include "btree.cpp" //该头文件为我自定义的头文件,其中的函数的声明和实现在我的博客中有
#include
//函数声明
bitree InTree(char s[], int i, int j); //中缀表达式建树过程
bitree PosTree(char s[], int len ); //后缀表达式建树过程
bitree PerTree(char s[], int len ); //前缀表达式建树过程
//前缀表达式建树过程 - 由于操作数在叶节点位置和前缀表达式的特点,其建树过程与后缀表达式一致,只不过扫描方向正好相反
bitree PerTree(char s[], int len)
{
// cout << "len:" << len << endl;
//计数变量
int i;
bitree p, root;
//临时栈 - 用来存放指向树节点的指针
struct stack
{
bitnode *vec[MaxSize];
int top;
} ;
struct stack q;
q.top = 0;
//遍历字符串,若为操作数 - 则生成根节点并将指向该根节点的指针入栈、若为运算符 - 则生成节点并在临时栈中弹出两个指向操作数
//节点的指针,并指向该运算符节点并将其入栈
for( i = len-1; i >= 0; i-- )
{
//为操作符
if( s[i] == '+' || s[i] == '/' || s[i] == '*' || s[i] == '-' )
{
p = (bitree)malloc(sizeof(bitnode));
p->data = s[i];
p->left = q.vec[q.top--]; //先弹出的为左节点
p->right = q.vec[q.top--]; //后弹出的为右节点
q.vec[++q.top] = p; //将根节点入栈
}
else
{
//s[i]为操作数
p = (bitree)malloc(sizeof(bitnode));
p->data = s[i];
p->left = NULL;
p->right = NULL;
q.vec[++q.top] = p; //将指向操作数节点的指针入栈
}
}
root = q.vec[q.top--]; //这一步很关键,因为该二叉树的根节点最后被保留在了栈中
return root;
}
//中缀表达式建树过程 - 递归过程
bitree InTree(char s[], int i, int j) //s - 表达式字符串、i - 字符串起始位置、j - 字符串最后一个字符的位置
{
//动态生成的树节点
bitree p;
int k, flag = 0, pos;
//如果i == j,则说明字符串只有一个字符,即为叶子节点、则创建只有一个根节点的二叉树并返回
if (i == j)
{
p = (bitree)malloc(sizeof(bitnode));
p->data = s[i];
p->left = NULL;
p->right = NULL;
return p;
}
//以下是 i != j的情况
//从左往右找最后一个+或-,先找+或-为了体现先乘除后加减的原则
for (k = i; k <= j; k++)
{
if (s[k] == '+' || s[k] == '-')
{
flag = 1;
pos = k;
}
}
//若没有+或-,则寻找字符串中最后一个*或/
if (flag == 0)
{
for (k = 0; k <= j; k++)
{
if (s[k] == '*' || s[k] == '/')
{
flag = 1;
pos = k;
}
}
}
//若flag不等于0,则以pos为界将字符串分为左右两部分,分别对应表达式二叉树的左、右子树
//同样以最后的运算符为根,将串分为两部分
//创建一个根节点、将找到的运算符放入
if (flag != 0)
{
p = (bitree)malloc(sizeof(bitnode));
p->data = s[pos];
p->left = InTree(s, i, pos - 1); //递归调用自身进入其左子树建树过程
p->right = InTree(s, pos + 1, j); //递归调用自身进入其右子树建树过程
return p;
}
else
return NULL;
}
//后缀表达式建树过程
bitree PosTree(char s[], int len)
{
// cout << "len:" << len << endl;
//计数变量
int i;
bitree p, root;
//临时栈 - 用来存放指向树节点的指针
struct stack
{
bitnode *vec[MaxSize];
int top;
} ;
struct stack q;
q.top = 0;
//遍历字符串,若为操作数 - 则生成根节点并将指向该根节点的指针入栈、若为运算符 - 则生成节点并在临时栈中弹出两个指向操作数
//节点的指针,并指向该运算符节点并将其入栈
for( i = 0; i < 9; i++ )
{
//为操作符
if( s[i] == '+' || s[i] == '/' || s[i] == '*' || s[i] == '-' )
{
p = (bitree)malloc(sizeof(bitnode));
p->data = s[i];
p->right = q.vec[q.top--]; //先弹出的为右节点
p->left = q.vec[q.top--]; //后弹出的为左节点
q.vec[++q.top] = p; //将根节点入栈
}
else
{
//s[i]为操作数
p = (bitree)malloc(sizeof(bitnode));
p->data = s[i];
p->left = NULL;
p->right = NULL;
q.vec[++q.top] = p; //将指向操作数节点的指针入栈
}
}
root = q.vec[q.top--]; //这一步很关键,因为该二叉树的根节点最后被保留在了栈中
return root;
}
int main()
{
bitree root;
char s[MaxSize];
cout << "中缀表达式:";
cin >> s;
root = InTree(s, 0, strlen(s) - 1);
cout << "表达式二叉树" << endl;
DispTree(root);
cout << endl;
cout << "该表达式二叉树三种遍历" << endl;
cout << "前序遍历:";
PerOrder(root);
cout << endl;
cout << "中序遍历:";
InOrder(root);
cout << endl;
cout << "后序遍历:";
PostOrder(root);
cout << endl;
cout << "后缀表达式:";
cin >> s;
root = PosTree(s,strlen(s));
cout << "表达式二叉树" << endl;
DispTree(root);
cout << endl;
cout << "前缀表达式:";
cin >> s;
root = PerTree(s,strlen(s));
cout << "表达式二叉树" << endl;
DispTree(root);
cout << endl;
root = FreeTree(root);
if (root == NULL)
cout << "释放成功" << endl;
return 0;
}