原博地址:http://lib.csdn.net/article/datastructure/15516
转载供以后研究
中缀表达式与后缀表达式
例:
(1)8+4-6*2用后缀表达式表示为:
62*84+-
35+2*71/4-+
中缀表达式转为后缀表达式(又称逆波兰表达式)的方法
逆波兰算法-栈实现
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入逆
波兰
式的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(2)若取出的字符是
运算符
,则将该运算符与S1栈栈顶元素比较,如果该
运算符优先级
大于S1栈栈顶
运算符
优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,则将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈底。
(5)重复上面的1~4步,直至处理完所有的输入字符
//#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<stack>
#include<math.h>
#include<string.h>
#definemax100
usingnamespacestd;
charex[max];/*存储后缀表达式*/
void trans()
{/*将算术表达式转化为后缀表达式*/
charstr[max];/*存储原算术表达式*/
charstack[max];/*作为栈使用*/
charch;
intsum,i,j,t,top=0;
printf("*****************************************\n");
printf("*输入一个求值的表达式,以#结束。*\n");
printf("******************************************\n");
printf("算数表达式:");
i=0;/*获取用户输入的表达式*/
do{
i++;
//cin>>str[i];/*此步我用的是C++C语言的话在后面之所以用这个有一点区别都*/
scanf("%c",&str[i]);
}while(str[i]!='#'&&i!=max);
sum=i;
t=1;i=1;
ch=str[i];i++;
//
while(ch!='#')
{
switch(ch)
{
case'(':/*判定为左括号*/
top++;stack[top]=ch;
break;
case')':/*判定为右括号*/
while(stack[top]!='(')
{
ex[t]=stack[top];top--;t++;
}
top--;
break;
case'+':/*判定为加减号*/
case'-':
while(top!=0&&stack[top]!='(')
{
ex[t]=stack[top];
top--;
t++;
}
top++;
stack[top]=ch;
break;
case'*':/*判定为乘除号*/
case'/':
while(stack[top]=='*'||stack[top]=='/')
{
ex[t]=stack[top];
top--;
t++;
}
top++;
stack[top]=ch;
break;
case'':break;
default:
while(ch>='0'&&ch<='9')
{/*判定为数字*/
ex[t]=ch;t++;
ch=str[i];i++;
}
i--;
ex[t]='';t++;
}
ch=str[i];i++;
}
while(top!=0)
{
ex[t]=stack[top];
t++;top--;
}
ex[t]='';
printf("\n\t原来表达式:");
for(j=1;j<sum;j++)
printf("%c",str[j]);
printf("\n\t逆波兰式:",ex);
for(j=1;j<t;j++)
printf("%c",ex[j]);
}
void compvalue()
{/*计算后缀表达式的值*/
floatstack[max],d;/*作为栈使用*/
charch;
intt=1,top=0;/*t为ex下标,top为stack下标*/
ch=ex[t];t++;
while(ch!='')
{
switch(ch)
{
case'+':
stack[top-1]=stack[top-1]+stack[top];
top--;
break;
case'-':
stack[top-1]=stack[top-1]-stack[top];
top--;
break;
case'*':
stack[top-1]=stack[top-1]*stack[top];
top--;
break;
case'/':
if(stack[top]!=0)stack[top-1]=stack[top-1]/stack[top];
else
{
printf("\n\t除零错误!\n");
exit(0);/*异常退出*/
}
top--;
break;
default:
d=0;
while(ch>='0'&&ch<='9')
{
d=10*d+ch-'0';/*将数字字符转化为对应的数值*/
ch=ex[t];t++;
}
top++;
stack[top]=d;
}
ch=ex[t];
t++;
}
printf("\n\t计算结果:%g\n",stack[top]);
}
intmain()
{
trans();
compvalue();
system("pause");
return0;
}
逆波兰算法-二叉树实现
#include <string>
#include <stack>
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
//节点类
class TNode
{
public:
friend class calculator_tree;
string father;
TNode *left, *right;
TNode()
{
left = right = NULL;
}
TNode(string a)
{
father = a;
left = right = NULL;
}
};
class calculator_tree
{
public:
calculator_tree() {
}
calculator_tree(string expression) {
getexpression(expression);
}
//获得算术表达式
void getexpression(string expression) { e = expression;
}
~calculator_tree() {
}
//返回中缀表达式
string ShowMiddleExpression() {
return e;
}
//计算函数, 输入为两个数和一个操作符, 返回值为计算结果(字符串形式)
string calculate(string num2, string num1, string op) {
double n2, n1;
string result;
stringstream x;
x << num2;
x >> n2;
x.clear();
x << num1;
x >> n1;
x.clear();
if (op == "+")
x << (n2 + n1);
if (op == "-")
x << (n2 - n1);
if (op == "*")
x << (n2 * n1);
if (op == "/")
x << (n2 / n1);
x >> result;
x.clear();
return result;
}
//判别符号的优先级
int Priority(char a) {
if (a == '(')
return 0;
else if (a == '+' || a == '-')
return 1;
else if (a == '*' || a == '/')
return 2;
return 0; }
//用于去除输入中多余的空格 输入为要除去空格的算术表达式 返回去掉空格的算术表达式
string RidSpace(string origin) {
string transfer;
for (int i = 0; i < origin.length(); i++) {
if (origin[i] != ' ')
transfer += origin[i];
}
return transfer;
}
//中缀表达式转后缀表达式, 因为要兼容多位数, 括号, 负数和小数等功能,
//由于多位数在转为后缀表达式时会分不清, 故在每个数和运算符后面加上一个空格作为区别
//expression为输出的后缀表达式
string MidToLast(string str) {
str = RidSpace(str);
string expression = "";
string number = "";
char x;
stack<char> op;
for (int i = 0; i < str.length(); ) {
//第一位做特殊处理 判断是否为负号
if (i == 0 && str[i] == '-') {
number = "-";
i++;
}
x = str[i];
//录入数字
if ((x >= '0' && x <= '9') || number == "-" || x == '.') {
while ((str[i] >= '0' && str[i] <= '9') || str[i] == '.') {
number += str[i];
i++;
}
expression += number;
//加空格以区别
expression += " ";
number = "";
continue;
} else {
//判断是括号还是运算符
if (x == '(') { op.push(x);
//判断是否为负号
if (str[i+1] == '-') {
number = "-";
i++;
}
} else {
//遇到右括号直接弹出运算符栈里的运算符到表达式中 运算符后加空格以区别
if (x == ')') {
while (op.top() != '(') {
expression += op.top();
expression += " ";
op.pop();
}
//弹出右括号
op.pop();
} else {
//弹出栈中优先级较高的运算符 运算符后加空格以区别
while (!op.empty() && (Priority(op.top()) >= Priority(x))) {
expression += op.top();
expression += " ";
op.pop();
}
//判断是否为负号
if (str[i+1] == '-') {
number = "-";
i++;
}
//将运算符压入栈
op.push(x);
}
}
}
i++;
}
while (!op.empty()) {
expression += op.top();
expression += " ";
op.pop();
}
return expression;
}
//获得后缀表达式
string GetLastExpression() {
return MidToLast(RidSpace(e));
}
//生成一棵二叉树
void makeTree(TNode *&p) {
stack <TNode*> Nodes;
string le = GetLastExpression();
string tem = "";
for (int i = 0; i < le.length(); ) {
while (le[i] != ' ') {
tem += le[i];
i++;
}
//若为数字, 压入结点栈
if (tem.length() > 1 || (tem.length() == 1 && tem[0] >= '0' && tem[0] <= '9'))
{
p =new TNode(tem);
Nodes.push(p);
} else {
//若为运算符 且栈非空 将栈顶元素拿出来分别作为左子树跟右子树的结点
//处理如-()的情况
if (Nodes.empty()) {
tem = "-";
i++;
continue;
}
p = new TNode(tem);
if (!Nodes.empty()) {
p -> right = Nodes.top();
Nodes.pop();
}
if (!Nodes.empty()) {
p -> left = Nodes.top();
Nodes.pop();
}
Nodes.push(p);
}
i++;
tem = "";
}
}
//后序遍历二叉树并计算 将计算结果返回
string PostOrder(TNode *p)
{
if(p) {
//假如为符号 执行计算后返回计算结果
if ((p->father).length() == 1 && Priority((p->father)[0])) {
PostOrder(p->right);
return calculate(PostOrder(p->left), PostOrder(p->right), p->father);
} else {
//假如为数字, 直接返回
return p->father;
}
}
}
private:
//存放输入的表达式
string e;
};
后缀表达式生成二叉树
一、定义
二叉树(binary tree)是一棵每个结点都不能有多于两个儿子的树。
二、数据结构设计
因为一个二叉树结点最多是有两个儿子,所以可以直接链接到他们。树结点的声明在结构上类似双向链表的声明。在声明中,一个结点就是由element(元素)的信息加上两个 到其他结点的引用(left和right)组成的结构
struct BinaryNode
{
Object element; //The data in the node
struct BinaryNode *left; //Left child
struct BinaryNode *right; //Right child
};
三、表达式树
表达式树的树叶是操作数(operand),加常数或变量名字,而其他的结点为操作数(operator)。由于这里所有的操作都是二元的,因此这棵特定的树正好是二叉树,虽然这是最简单的情况,但是结点还是有可能含有多于两个的儿子,这里我们不讨论。
四、构造一棵表达式树
之前我们实现过一个中缀表达式求值的具体程序,在求值过程中需要用两个栈,并且代码并不简单。而这里你会看到,对于表达式树的求值操作却非常简单,甚至只需要两条语句。因为这里大部分操作都是递归定义,二递归函数本身都是很简洁的,甚至比你想象的还要简单,甚至只需要两条语句。因为这里大部分操作都是递归定义,二递归函数本身都是很简洁的,甚至比你想象的还要简单!就像树的遍历操作。三种遍历分别是先序遍历、中序遍历与后序遍历,正好对应表达式的三种形式:前缀型、中缀型与后缀型。其中为大家熟知的是中缀形式,如2+3*(5-4)。前缀型表达式又叫波兰式(Polish Notation),后缀性表达式又叫逆波兰式(Reverse Polish Notation)。他们最早于1920年波兰数学家Jan Lukasiewicz发明,这两种表示方式的最大特点是不需要括号来表明优先级,他们经常用于计算机科学,特别是编译器设计方面。
下面给出一种算法来把后缀表达式转变成表达式树。我们一次一个符号地读入表达式。如果符号是操作数,那么就建立一个单结点树并将它推入栈中。如果符号是操作符,那么就从栈中弹出两棵树T1和T2(T1先弹出)并形成一棵新的树,该树的根就是操作符,它的左、右儿子分别是T2和T1。然后将指向这颗树的指针压入栈中。
下面来看一个例子。设输入为ab+cde+**
前两个符号是操作数,因此创建两棵单结点树并将指向它们的指针压入栈中。
接着,"+"被读入,因此指向两棵树的指针被弹出,形成一棵新的树,并将指向它的指针压入栈中。
然后,c,d和e被读入,在单个结点树创建后,指向对应的树的指针被压入栈中。
接下来读入"+"号,因此两棵树合并。
继续进行,读入"*"号,因此,弹出两棵树的指针合并形成一棵新的树,"*"号是它的根。
最后,读入一个符号,两棵树合并,而指向最后的树的指针被留在栈中。
下面我们来实现以下它吧
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
//树结点的设计
typedef struct node
{
//数字和运算符
union
{
char operator;
int data;
};
struct node *lchild;
struct node *rchild;
}TreeNode;
//树栈的设计
typedef struct
{
TreeNode *buf[MAX];
int n;
}TreeStack;
//创建空栈
TreeStack *create_empty_stack()
{
TreeStack *pstack;
pstack = (TreeStack *)malloc(sizeof(TreeStack));
pstack->n = -1;
return pstack;
}
//入栈
int push_stack(TreeStack *p,TreeNode *data)
{
p->n ++;
p->buf[p->n] = data;
return 0;
}
//出栈
TreeNode *pop_stack(TreeStack *p)
{
TreeNode *data;
data = p->buf[p->n];
p->n --;
return data;
}
//判断空栈
int is_empty_stack(TreeStack *p)
{
if(p->n == -1)
{
return 1;
}else{
return 0;
}
}
//后缀表达式树的创建
TreeNode *create_express_tree(char *str,TreeStack *p)
{
int i = 0;
TreeNode *current;
TreeNode *left,*right;
while(str[i])
{
if(str[i] == ' ')
{
i ++;
continue;
}
if(str[i] >= '0' && str[i] <= '9')
{
current = (TreeNode *)malloc(sizeof(TreeNode));
current->data = str[i] - '0';
current->lchild = current->rchild = NULL;
push_stack(p,current);
}else{
current = (TreeNode *)malloc(sizeof(TreeNode));
current->operator = str[i];
right = pop_stack(p);
left = pop_stack(p);
current->lchild = left;
current->rchild = right;
push_stack(p,current);
}
i ++;
}
return p->buf[p->n];
}
//打印结点
void print_node(TreeNode *p)
{
if(p->lchild == NULL && p->rchild == NULL)
{
printf("%d ",p->data);
}else{
printf("%c ",p->operator);
}
return;
}
//访问结点
int vist_node(TreeNode *p)
{
print_node(p);
return 0;
}
//树的后序遍历
int PostOrder(TreeNode *p)
{
if(p != NULL)
{
PostOrder(p->lchild);//左
PostOrder(p->rchild);//右
vist_node(p);//根
}
return 0;
}
//树的中序遍历
int InOrder(TreeNode *p)
{
if(p != NULL)
{
InOrder(p->lchild);//左
vist_node(p);//根
InOrder(p->rchild);//右
}
return 0;
}
//树的前序遍历
int PreOrder(TreeNode *p)
{
if(p != NULL)
{
vist_node(p);//根
PreOrder(p->lchild);//左
PreOrder(p->rchild);//右
}
return 0;
}
/队列的设计
struct _node_
{
TreeNode *data;
struct _node_ *next;
};
typedef struct
{
struct _node_ *front;
struct _node_ *rear;
}Queue;
//创建空队列
Queue *create_empty_queue()
{
struct _node_ *pnode;
Queue *qhead;
qhead = (Queue *)malloc(sizeof(Queue));
pnode = (struct _node_ *)malloc(sizeof(struct _node_));
pnode->next = NULL;
qhead->front = qhead->rear = pnode;
return qhead;
}
//入队
int EnterQueue(Queue *qhead,TreeNode *data)
{
struct _node_ *temp;
temp = (struct _node_ *)malloc(sizeof(struct _node_ *));
temp->data = data;
temp->next = NULL;
qhead->rear->next = temp;
qhead->rear = temp;
return 0;
}
//出队
TreeNode *DeleteQueue(Queue *qhead)
{
struct _node_ *temp;
temp = qhead->front;
qhead->front = temp->next;
free(temp);
temp = NULL;
return qhead->front->data;
}
//队列为空
int is_empty_queue(Queue *qhead)
{
if(qhead->front == qhead->rear)
return 1;
else
return 0;
}
//树的层次遍历
int NoOrder(TreeNode *p)
{
Queue *qhead;
TreeNode *pdata;
qhead = create_empty_queue();
EnterQueue(qhead, p);
while(!is_empty_queue(qhead))
{
pdata = DeleteQueue(qhead);
vist_node(pdata);
if(pdata->lchild)EnterQueue(qhead,pdata->lchild);
if(pdata->rchild)EnterQueue(qhead,pdata->rchild);
}
return 0;
}
int main()
{
TreeNode *thead;
TreeStack *pstack;
int i = 0;
char buf[100];
while((buf[i++] = getchar()) != '\n' && i < 100);
buf[i-1] = 0;
pstack = create_empty_stack();
thead = create_express_tree(buf,pstack);
printf("PostOrder:: ");
PostOrder(thead);
printf("\n");
printf("InOrder:: ");
InOrder(thead);
printf("\n");
printf("PreOrder:: ");
PreOrder(thead);
printf("\n");
printf("NoOrder::");
NoOrder(thead);
printf("\n");
return 0;
}