目录
语法树
中缀表达式
前缀表达式
后缀表达式
根据中缀表达式创建语法树
根据前缀表达式创建二叉树
根据后缀表达式计算结果
语法树
语法树即将运算符作为根节点,将数字作为左右节点。
下面以中缀表达式A+B*(C-D)+E/F为例画出一颗语法树,步骤:
(1)从当前的中缀表达式中选择最后执行的四则运算符,作为当前的根节点,若没有运算符,将数字写在对应的节点处;
(2) 该运算符将中缀表达式分为左右两部分,即为左右子树,重复步骤(1);
中缀表达式
中缀表达式是一个通用的算术或逻辑公式表示方法。 中缀表达式就是我们通常理解的表达式,如13+5*(2-0)。中序遍历语法树即可得到中缀表达式。
前缀表达式(波兰式)
前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面。 先序遍历语法树可得到前缀表达式,上图的前缀表达式为:++A*B-CD/EF。
后缀表达式(逆波兰式)
后缀表达式即将运算符写在操作数之后 后序遍历语法树可得到后缀表达式,上图的后缀表达式为:ABCD-*+EF/+。
根据中缀表达式创建二叉树,并通过层次遍历验证树的结构
思路:
(1)遍历字符数组,若为数字则创建节点并存入节点栈;
(2)若为运算符,当运算符栈为空则直接入栈;
(3)若为运算符,当运算符不为空且运算符优先级比运算符栈顶元素低时,将运算符存入运算符栈并为数组下一位创建节点存入节点栈;当运算符栈不为空时,循环取出栈顶元素创建节点并连接节点栈中元素(先连接右节点再连接左节点);
(4)判断运算符栈是否为空,若不为空,则取出栈顶元素为其创建节点并连接节点栈中元素。
struct tree
{
char c;
struct tree* left;
struct tree* right;
};
stack<struct tree*> subTreeStack; //节点栈
stack<char> operatorStack; //运算符栈
struct tree* BuildTree(char str[])
{
struct tree* node;
for (unsigned int pos = 0; pos < strlen(str); pos++)
{
if (str[pos] - '0' >= 0 && str[pos] - '0' <= 9) //若是数字则作为叶子节点
{
node = (struct tree*) malloc(sizeof(struct tree));
node->c = str[pos];
node->left = NULL;
node->right = NULL;
subTreeStack.push(node);
}
else if (str[pos] == '*' || str[pos] == '/' || str[pos] == '+' || str[pos] == '-')
{
if (!operatorStack.empty() && (str[pos] == '+' || str[pos] == '-')) //若优先级比栈顶元素低
{
operatorStack.push(str[pos]);
node = (struct tree*) malloc(sizeof(struct tree));
node->c = str[pos+1];
node->left = NULL;
node->right = NULL;
subTreeStack.push(node);
while(!operatorStack.empty()){
node = (struct tree*) malloc(sizeof(struct tree));
node->c = operatorStack.top();
node->right = subTreeStack.top();
subTreeStack.pop();
node->left = subTreeStack.top();
subTreeStack.pop();
subTreeStack.push(node);
operatorStack.pop();
}
pos++;
}
else
operatorStack.push(str[pos]);
}
}
while (!operatorStack.empty())
{
node = (struct tree*) malloc(sizeof(struct tree));
node->c = operatorStack.top();
operatorStack.pop();
node->right = subTreeStack.top();
subTreeStack.pop();
node->left = subTreeStack.top();
subTreeStack.pop();
subTreeStack.push(node);
}
return subTreeStack.top();
}
int BiTree_height(struct tree* root)//求树的深度算法
{
if(root==NULL)
return 0;
else
{
if(BiTree_height(root->left)>BiTree_height(root->right))
return 1+BiTree_height(root->left);
else
return 1+BiTree_height(root->right);
}
}
void printNodeAtLevel(struct tree* root,int level)
{
if(root==NULL||level<0)
return;
if(level==0)
{
printf("%c ",root->c);
return;
}
// 左子树的 level - 1 级
printNodeAtLevel(root->left,level-1);
// 右子树的 level - 1 级
printNodeAtLevel(root->right,level-1);
}
//将树按层次遍历
void levelOrder(struct tree* root)
{
if(root==NULL)
return;
int totalLevel = BiTree_height(root);
for(int i = 0; i< totalLevel; i++)
{
printNodeAtLevel(root, i);
cout<<endl;//打印完一层,换行
}
}
根据前缀表达式递归创建二叉树
即根据先序遍历序列递归创建二叉树,当结点没有左右孩子时用‘#’表示为空,上图语法树结构如下图所示:
实现代码如下:
typedef struct BiTNode
{
char data;
struct BiTNode *lchild, *rchild;;
}BiTNode, *BiTree;
int CreateBiTree(BiTree &T)
{
//按先序次序输入二叉树中的结点的值(一个字符), #表示空树
//构造二叉链表表示的二叉树T
char a;
scanf("%c",&a);
if(a == '#')
T = NULL;
else{
T=(BiTNode *)malloc(sizeof(BiTNode));
T->data = a;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
return 1;
}
根据后缀表达式计算结果
思路:
(1)将后缀表达式存入字符数组中,定义数字数组用于存操作数,并且定义top变量充当指针功能;
(2)遍历字符数组,倘若为操作数则直接存入数字数组中,top++;
(3)倘若为运算符,则从数字数组中取出两个数进行四则运算。注意:先取出右操作数,后取出左操作数。
(4)将计算结果重新写入数字数组中覆盖原先操作数;
(5)循环以上操作,直到遍历结束。
//基本四则运算
int cal(char op,int a,int b)
{
if(op == '+')
return a + b;
if(op == '-')
return a - b;
if(op == '*')
return a * b;
if(op == '/'){
if(b == 0){
cout<<"Error!"<<endl;
return 0;
}
else{
return a / b;
}
}
return 1;
}
//逆波兰表达式求结果
int ReversePolishCal(char exp[])
{
int len = strlen(exp);
int stack[100], top=-1;
int a, b, c;
char op;
for(int i=0;i<len;i++){
if(exp[i] - '0' >= 0 && exp[i] - '0' <= 9){
stack[++top] = exp[i] - '0';
}
else{
op = exp[i];
b = stack[top--];
a = stack[top--];
c = cal(op, a, b);
stack[++top] = c;
}
}
return stack[top];
}