表达式求值
要了解算术四则运算规则
1)先乘除,后加减
2)从左算到右
3)先括号内再括号外
表达式由操作数、运算符、界限符组成,后两个通称为算符,任意相继出现的两个算符r1 r2有优先权的比较(r1代表当前栈顶元素,r2代表表达式中的字符)
算符间的优先关系详见课本53页
第一步 置操作数栈为空栈,起始符"#"作为运算符栈的栈底元素
第二步:依次读入表达式每个字符,利用算符间的优先关系,若r1<r2,r2入栈,继续向后扫描
若r1>r2,r1出栈,继续向后比较,直至某一字符入栈
若r1=r2,遇到“#”结束循环
练习中缀表达式的转换
A+B*(C-D*(E+F)/G+H)-(I+J)*K
序列为:ABCDEF+*G/-H+ *+ I J + K * -
当碰到左括号时,先计算的是括号里面的值,优先级大于里面的运算符
算法实现的基本思想
第一步 置操作数栈为空栈,起始符"#"作为运算符栈的栈底元素
第二步:依次读入表达式每个字符,利用算符间的优先关系,若r1<r2,r2入栈,继续向后扫描
若r1>r2,r1出栈,继续向后比较,直至某一字符入栈
若r1=r2,遇到“#”结束循环
是操作数,进入OPND栈,运算符和OPTR栈的栈顶运算符比较优先权在操作
int EvaluateExpression(char ch[])
{
int i=0,j;
int x1,x2,x;
SElemType e;
char top,oper;
LinStack optr,opnd;//optr为运算符堆栈,opnd为运算数堆栈
InitStack(&optr);//初始化运算符堆栈
Push(&optr,'#');//将#号入堆栈
InitStack(&opnd);
GetTop(optr,&e);
top=e;//top为运算符栈顶元素
printf("%c",top);
while((ch[i]!='#')&&(top!='#')){
printf("%c",ch[i]);
if(ch[i]>='0'&&ch[i]<='9'){//如果扫描到运算数 ,则入栈
Push(&opnd,ch[i]);
i++;
printf("操作数入栈\n");
}else{
GetTop(opnd,&e);
top=e;
printf("%c",top);
j=Precede(top,ch[i]);
if(j==-1){//栈顶运算符优先级低
Push(&optr,ch[i]);
i++;
printf("运算符入栈\n");
}else{
if(j==0){//栈顶运算符和扫描到的运算符优先级相同,且为括号时
Pop(&optr,&e);
i++;
printf("括号\n");
}else{//栈顶运算符优先级高
Pop(&opnd,&e);
x1=e;
Pop(&opnd,&e);
x2=e;
Pop(&optr,&e);
oper=e;
switch(oper){
case '+':x=x2+x1;break;
case '-':x=x2-x1;break;
case '*':x=x2*x1;break;
case '/':x=x2/x1;break;
}
Push(&opnd,x);
printf("运算符出栈,进行运算\n");
}
}
}
}
GetTop(opnd,&e);
return e;
}
int Precede(char ch1,char ch2){
if((ch1==’+’||ch2==’-’)&&(ch2==’+’||ch2==’-’||ch2==’)’||ch2==’#’)){
return 1;.
}
if((ch1==’+’||ch2==’-’)&&(ch2==’’||ch2==’/’||ch2==’(’)){
return -1;
}
if((ch1==’’||ch1==’/’)&&(ch2==’+’||ch2==’-’||ch2==’)’||ch2==’#’||ch2==’’||ch2==’/’)){
return 1;
}
if((ch1==’’||ch1==’/’)&&(ch2==’(’)){
return -1;
}
if(ch1==’(’&&ch2==’+’||ch2==’-’||ch2==’(’||ch2==’’||ch2==’/’){
return -1;
}
if(ch1==’(’&&ch2==’)’){//优先级相同,返回0
return 0;
}
if(ch1==’)’&&(ch2==’+’||ch2==’-’||ch2==’’||ch2==’/’||ch2==’)’||ch2==’#’)){
return 1;
}
if(ch1==’#’&&(ch2==’+’||ch2==’-’||ch2==’*’||ch2==’/’||ch2==’(’)){
return -1;
}
if(ch1==’#’&&ch2==’#’){
return 0;
}
}
二叉树的遍历
所谓遍历二叉树就是按某种顺序访问二叉树中的每个结点一次且仅一次的过程。这里的访问可以是输出、比较、更新、查看元素内容等等各种操作。
TLR(根左右)、LTR(左根右)和LRT(左右根)根据根访问的位置不同分别被称为先序遍历、中序遍历和后序遍历
相关算法实现
首先要建立好一颗二叉树
实现代码如下
typedef struct node
{
ElemType data;
struct node *lchild, *rchild;
} BTNode;
BTNode creatBiTree()静态建立一颗二叉树
{
BTNode a,b,c,d,e,f,g;
a.data=‘A’;
a.lchild=&b;
a.rchild=&c;
b.data=‘B’;
b.lchild=&d;
b.rchild=NULL;
c.data=‘C’;
c.lchild=&e;
c.rchild=&f;
…
return a;
}
按层次遍历二叉树
实现方法为从上层到下层,每层中从左侧到右侧依次访问每个结点。下面我们将给出一棵二叉树及其按层次顺序访问其中每个结点的遍历序列。
层次遍历算法
二叉树的建立
按照层次序列并进行相应的补空可以唯一确定一个二叉树
同时由先根、中根或中根、后根均可以唯一确定一个二叉树
这是根据左右子树以及根的确定,来根据序列画出二叉树图