在表达式二叉树的学习中,有很多有趣的构造其表达式二叉树的方法,其中先缀表达式构建表达式二叉树常见有很多都是利用递归的方式去构建,但在阅览的一篇文档中,引出了非递归方式构建其表达式二叉树概念,虽然相对更麻烦,但在其代码实现,探索上还是很有意义的.
先缀表达式构建表达式二叉树(非递归)
c语言实现:
先缀表达式:*-23+45
如图,如果从左到右读取先缀表达式,发现操作符就将其入栈,发现操作符的第二个操作数之后,将它们组织成最小的子树,然后操作符出栈,继续遍历下一个字符。在这个过程中,操作数是不入栈的,栈里只有操作符,当操作符组织成最小计算单元之后就将其出栈。当栈空的时候,说明先缀表达式遍历完毕。
结合其表达式二叉树图来理解:
先缀表达式:*-23+45
观察其表达式和二叉树图,从左往右读取,就是其二叉树的先序遍历,我们定义一个树节点指针记录其路径结点.
由于我们要构建的是二叉树,所以不管数字还是操作符都是树节点,每读取一个符号都要录入树节点中,而栈要存储的也是树节点.
首先遇到操作符就入栈,指针指向其左孩子节点,然后继续读取
如果遇到数字,就存入节点data中,并判定栈顶树节点符号是否存在右孩子节点,
若不存在右孩子节点,初始化其右孩子节点,并指针指向其右孩子节点,
若栈顶树节点已存在右孩子节点,说明栈顶符号已有两个数字孩子结点,这样就构成一个基本算式单元,栈顶节点出栈,
指针继续指向栈顶元素,并继续判定栈顶树节点符号是否存在右孩子节点
直到栈顶右孩子节点不存在,或者其栈为空.
对栈内节点分析:
1.符号间为父子关系,且只为双亲与左孩子之间的关系,
2.其节点必定存在左孩子节点,在存在右孩子节点,并完成赋值后,就要进行出栈操作
3.栈内存的是树节点,当栈内一定保存的是树节点地址,即存的是树节点指针,而不是变量值,因为在对栈顶节点读取并存入右孩子时,要保证其树节点也发生变化.
C语言:
栈,树结构声明:
.h
//二叉树链式存储结构
typedef struct node {
char data;
struct node* lchild, * rchild;
}BiTNode, *BiTree;
typedef BiTree ElemType;
//这里树节点一定要用指针,即符号节点入栈时存储地址,而不是值
//这样在对栈内的树节点修改数据时,对树节点才能起到真正影响
typedef struct {
ElemType data[MAXSIZE];
int top;
}SqStack,* SqStackS; //顺序栈
int InitStack(SqStackS* S);
int StackEmpty(SqStackS S);
int Push(SqStackS S, ElemType x);
int Pop(SqStackS S);
int Pops(SqStackS S, ElemType* x);
int GetTop(SqStackS S, ElemType* x);
.c
#include "Stack_Tool.h"
#include<stdlib.h> //动态分配函数和随机函数
#include<stdio.h>//输入输出
//由于此模块中使用了malloc()函数,其是<stdlib.h>库中的内容,若不引入库,将无法动态分配内存,
//就会导致动态内存分配失败,变量<无法读取内存>
int InitStack(SqStackS *S) {
*S = (SqStackS)malloc(sizeof(SqStack));
(*S)->top = -1;
return 1;
}
int StackEmpty(SqStackS S) {
if (S->top == -1)
return 1;
else
return 0;
}
int Push(SqStackS S, ElemType x) {
if (S->top == MAXSIZE - 1)
return 0;
S->data[++S->top] =x; //指针先加一,再入栈
return 1;
}
int Pop(SqStackS S) {
if (S->top == -1)
return 0;
S->top--;
return 1;
}
int Pops(SqStackS S, ElemType *x) {
if (S->top == -1)
return 0;
*x = S->data[S->top--]; //先出栈,指针再减一
return 1;
}
//获取栈顶成员的地址,通过栈指针获取栈地址位置,然后通过二级指针返回其成员地址
//这里由于栈内保存的是指针,而以及指针虽然传递的是地址,但却是树节点类型的指针地址
//而我们要保存树节点的指针的地址,就需要树节点的指针的类型指针,也就是二级指针
int GetTop(SqStackS S, ElemType* x) {
if (S->top == -1)
return 0;
*x = S->data[S->top];
return 1;
}
main.c
char nextToken(char formula[]) {
static int pos = 0; //static pos只初始化一次,且持续累积
while (formula[pos] != '\0' && formula[pos] == ' ') { pos++; }//跳过空格
return formula[pos++];
}
int isOpNum(char ch) {
if (ch == '+' || ch == '-' || ch == '*' || ch == '/'|| ch == '(' || ch == ')')
return 1;
else
return 0;
}
void createTree(BiTree* bt,char formula[]) {
char* c = formula;
SqStackS parentStack;
InitStack(&parentStack);
*bt= (BiTree)malloc(sizeof(BiTNode));
BiTree tpointer=*bt;
char single = nextToken(c);
while(single !='\0'){
if (isOpNum(single)) { //如果是字符,字符入栈,将指针指向其左孩子
tpointer->data = single;
tpointer->lchild = (BiTree)malloc(sizeof(BiTNode));
tpointer->rchild = NULL;
//进栈1,串栈指针即可,因为指针保存的是地址,对树节点无变化,使用值传递
Push(parentStack, tpointer);
tpointer = tpointer->lchild;
}
else { //如果是数字
tpointer->data = single;
GetTop(parentStack, &tpointer);
while (tpointer->rchild!=NULL){
Pop(parentStack);
if (StackEmpty(parentStack))
return;
GetTop(parentStack, &tpointer);
}
tpointer->rchild = (BiTree)malloc(sizeof(BiTNode));
tpointer = tpointer->rchild;
}
single = nextToken(c);
}
}
输出带括号的中缀表达式
//输出带括号的中缀表达式
void BtreeToExp(BiTree btt, int deep) {
if (btt == NULL)
return;
else if (isOpNum(btt->data)) {
if (deep > 1)
printf("(");
BtreeToExp(btt->lchild, deep + 1);
printf("%c", btt->data);
BtreeToExp(btt->rchild, deep + 1);
if (deep > 1)
printf(")");
}
else {
printf("%c", btt->data);
}
}
void BtreeToE(BiTree btt) {
BtreeToExp(btt, 1);
}
递归对表达式二叉树运算
int yunSuan(int a, int b, char data) {
int count;
switch (data) {
case '+':
count = a + b;
break;
case '-':
count = a - b;
break;
case '*':
count = a * b;
break;
case '/':
count = a / b;
break;
}
return count;
}
//通过表达式二叉树,输出运算结果
int sum(BiTree btt) {
int count;
char data = btt->data;
//如果是符号
if (isOpNum(data)) {
int a = sum(btt->lchild);
int b = sum(btt->rchild);
//然后调用运算方法
//return 运算结果;
count=yunSuan(a, b, data);
return count;
}
count = data -48;
//将char转为int,然后返回
return count;
}
main()函数:
int main() {
BiTree bt=NULL;
char formula[20] ;
printf("给我要构建二叉树的先序表达式:\n");
//最新的VS2019中提供了scanf_s()。在调用时,可以提供一个数字以表明最多读取多少位字符。
scanf_s("%s", &formula,20);
createTree(&bt, formula);
//输出带括号的中缀表达式
printf("中缀表达式为:");
BtreeToE(bt);
printf("\n");
//构建完二叉树后,对二叉树进行计算.
//通过对左右递归
int count=sum(bt);
printf("计算结果是:%d", count);
}
测试: