一.简介

  迷宫求解:类似图的DFS。具体的算法思路可以参考书上的50、51页,不过书上只说了粗略的算法,实现起来还是有很多细节需要注意。大多数只是给了个抽象的名字,甚至参数类型,返回值也没说的很清楚,所以很多需要自己揣摩。这也体现了算法和程序设计语言的特点,算法更侧重本质的描述,而任何编程语言都要照顾到实现的细节以及数据类型等语法方面的需求。

  表达式求值:

  由于数据的读入是按照字符读入的,所以这个简单的小程序只能计算个位数的运算。

  二.头文件

  迷宫求解:

 //3_2_maze.h
/**
author:zhaoyu
email:zhaoyu1995.com@gmail.com
date:2016-6-8
note:realize my textbook <<数据结构(C语言版)>>
*/
//Page 51
#ifndef _3_2_MAZE_H
#define _3_2_MAZE_H
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "head.h"
#define STACK_INIT_SIZE 200//存储空间的初始分配值
#define STACKINCREMENT 10//存储空间分配增量
#define WALL -1
#define PATH 1
#define PASSED -2
#define UNREACHABLE -3
#define FINALPATH -4
#define NMAX 50
char Map[NMAX][NMAX];
typedef struct{
int x;
int y;
}PosType;
typedef struct node_1{
int x, y;
struct node_1 *next;
}MazeType;
typedef struct{
int ord;//通道块在路径上的序号
PosType seat;//通道块在迷宫中的位置
int direction;//从此通道块走向下一通道块的方向
}SElemType;
typedef struct{
SElemType *base;//在栈构造之前和销毁之后,base 值为 NULL
SElemType *top;//栈顶指针
int stacksize;//当前已分配的存储空间,以元素为单位
}SqStack;
Status InitStack(SqStack &S)
{
//构造一个空栈 S
S.base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
if (!S.base)
{
exit(OVERFLOW);
}
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}//InitStack
void Assign_PosType(PosType &a, PosType b)
{
a.x = b.x;
a.y = b.y;
}//Assign_PosType
Status Pass(PosType pos)
{//可能写的不对,注意
if (PATH == Map[pos.x][pos.y])
{
return TRUE;
}
else
{
return FALSE;
}
}//Pass
void FoorPrint(PosType pos)
{
Map[pos.x][pos.y] = PASSED;
}
void Assign_SELemType(SElemType &e, int x, PosType pos, int y)
{
e.ord = x;
Assign_PosType(e.seat, pos);
e.direction = y;
}
Status Push(SqStack &S, SElemType e)
{
//插入元素 e 为新的栈顶元素
if (S.top - S.base >= S.stacksize)
{//栈满,追加存储空间
S.base = (SElemType *)realloc(S.base,
(S.stacksize+STACKINCREMENT)*sizeof(SElemType));
if (!S.base)
{
exit(OVERFLOW);
}
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
//*S.top++ = e;
Assign_SELemType(*S.top++, e.ord, e.seat, e.direction);
return OK;
}//Push
PosType NextPos(PosType pos, int direction)
{
PosType temp;
switch (direction)
{
case :
{
temp.x = pos.x;
temp.y = pos.y+;
break;
}
case :
{
temp.x = pos.x + ;
temp.y = pos.y;
break;
}
case :
{
temp.x = pos.x;
temp.y = pos.y - ;
break;
}
case :
{
temp.x = pos.x - ;
temp.y = pos.y;
break;
}
}
//加一个越界检查
return temp;
}
Status StackEmpty(SqStack S)
{
//若 S 为空栈, 则返回 TRUE, 否则返回 FALSE
if (S.base == S.top)
{
return TRUE;
}
else
{
return FALSE;
}
}
Status Pop(SqStack &S, SElemType &e)
{
//若栈不空,则删除 S 的栈顶元素,用 e 返回其
//值,并返回OK;否则返回ERROR
if (S.top == S.base)
{
return ERROR;
}
//e = *--S.top;
S.top--;
Assign_SELemType(e, (*S.top).ord, (*S.top).seat, (*S.top).direction);
return OK;
}//Pop
void FootPrint(PosType pos)
{
Map[pos.x][pos.y] = PASSED;
}
void MarkPrint(PosType pos)
{
Map[pos.x][pos.y] = UNREACHABLE;
}
void MakeMap(int size)
{
memset(Map, , sizeof(Map));
char ch;
getchar();
for (int i = ; i <= size; i++)
{
for (int j = ; j <= size; j++)
{
scanf("%c", &ch);
if ('X' == ch)
{
Map[i][j] = UNREACHABLE;
}
else
{
Map[i][j] = PATH;
}
}
//attention '\n'
getchar();
}
//Print maze
for (int i = ; i <= size; i++)
{
for (int j = ; j <= size; j++)
{
if (UNREACHABLE == Map[i][j])
{
printf("X");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
void PrintPath(SqStack S, int size)
{
SElemType e;
SqStack temp;
while (!StackEmpty(S))
{
Pop(S, e);
Map[e.seat.x][e.seat.y] = FINALPATH;
}
for (int i = ; i <= size; i++)
{
for (int j = ; j <= size; j++)
{
if (UNREACHABLE == Map[i][j])
{
printf("X");
}
else if (FINALPATH == Map[i][j])
{
printf("O");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
Status MazePath(MazeType maze, PosType start, PosType end, int size)
{
//若迷宫 maze 中存在从入口 start 到出口 end 的通道,
//则求得一条存放在栈中(从栈底到栈顶),并返回 TRUE,
//否则返回 FALSE
SqStack S;
InitStack(S);
//curpos = start
PosType curpos;
Assign_PosType(curpos, start);//设定当前位置为入口位置
int curstep = ;//探索第一步
SElemType e;
do{
if (TRUE == Pass(curpos))
{//当前位置可以通过
FootPrint(curpos);//留下足迹
//e = (curstep, curpos, 1);
Assign_SELemType(e, curstep, curpos, );
Push(S, e);//加入路径
if (curpos.x == end.x && curpos.y == end.y)
{
//打印路径
printf("PATH EXIST\n");
PrintPath(S ,size);
return TRUE;
}
curpos = NextPos(curpos, );//下一位置是当前位置的东邻
curstep++;//探索下一步
}
else
{
if (!StackEmpty(S))
{
Pop(S, e);
while ( == e.direction && !StackEmpty(S))
{
MarkPrint(e.seat);
Pop(S, e);//留下不能通过的标记,并退回一步
}
if (e.direction < )
{
e.direction++;
Push(S, e);
curpos = NextPos(e.seat, e.direction);
}
}
}
}while (!StackEmpty(S)); }
#endif

3_2_maze.h

  表达式求值:

 //3_2_maze.h
/**
author:zhaoyu
email:zhaoyu1995.com@gmail.com
date:2016-6-8
note:realize my textbook <<数据结构(C语言版)>>
*/
//Page 53
#ifndef _3_2_EXPRESSION_H_
#define _3_2_EXPRESSION_H_
#include "head.h" #define SElemType char
#define OperandType float
#define STACK_INIT_SIZE 100//存储空间的初始分配值
#define STACKINCREMENT 10//存储空间分配增量
typedef struct{
SElemType *base;//在栈构造之前和销毁之后,base 值为 NULL
SElemType *top;//栈顶指针
int stacksize;//当前已分配的存储空间,以元素为单位
}SqStack_Char;
typedef struct{
OperandType *base;//在栈构造之前和销毁之后,base 值为 NULL
OperandType *top;//栈顶指针
int stacksize;//当前已分配的存储空间,以元素为单位
}SqStack_Float;
Status InitStack_Char(SqStack_Char &S)
{
//构造一个空栈 S
S.base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
if (!S.base)
{
exit(OVERFLOW);
}
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}//InitStack
Status InitStack_Float(SqStack_Float &S)
{
//构造一个空栈 S
S.base = (OperandType *)malloc(STACK_INIT_SIZE*sizeof(OperandType));
if (!S.base)
{
exit(OVERFLOW);
}
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}//InitStack
Status Push_Char(SqStack_Char &S, SElemType e)
{
//插入元素 e 为新的栈顶元素
if (S.top - S.base >= S.stacksize)
{//栈满,追加存储空间
S.base = (SElemType *)realloc(S.base,
(S.stacksize+STACKINCREMENT)*sizeof(SElemType));
if (!S.base)
{
exit(OVERFLOW);
}
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top++ = e;
return OK;
}//Push
SElemType GetTop_Char(SqStack_Char S)
{
//若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;
//否则返回ERROR
if (S.top == S.base)
{
return ERROR;
}
return *(S.top - );
}//GetTop
Status isInOPTR(SElemType c)
{
switch (c)
{
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
case '#':
{
return TRUE;
break;
}
default:
{
return FALSE;
break;
}
}
}
Status Push_Float(SqStack_Float &S, OperandType e)
{
//插入元素 e 为新的栈顶元素
if (S.top - S.base >= S.stacksize)
{//栈满,追加存储空间
S.base = (OperandType *)realloc(S.base,
(S.stacksize+STACKINCREMENT)*sizeof(OperandType));
if (!S.base)
{
exit(OVERFLOW);
}
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top++ = e;
return OK;
}//Push
char Precede(SElemType a, SElemType b)
{
char R[][] = {{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},
{'>','>','>','>','<','>','>'},
{'<','<','<','<','<','=','#'},
{'>','>','>','>','#','>','>'},
{'<','<','<','<','<','#','='}};
int i,j;
switch (a)
{
case '+':i=;break;
case '-':i=;break;
case '*':i=;break;
case '/':i=;break;
case '(':i=;break;
case ')':i=;break;
case '#':i=;break;
default:i=;break;
}
switch (b)
{
case '+':j=;break;
case '-':j=;break;
case '*':j=;break;
case '/':j=;break;
case '(':j=;break;
case ')':j=;break;
case '#':j=;break;
default:j=;break;
}
if ('#' == R[i][j])
{
printf("ERROR\n");
exit(ERROR);
}
else
{
return R[i][j];
}
}
Status Pop_Char(SqStack_Char &S, SElemType &e)
{
//若栈不空,则删除 S 的栈顶元素,用 e 返回其
//值,并返回OK;否则返回ERROR
if (S.top == S.base)
{
return ERROR;
}
e = *--S.top;
return OK;
}//Pop
Status Pop_Float(SqStack_Float &S, OperandType &e)
{
//若栈不空,则删除 S 的栈顶元素,用 e 返回其
//值,并返回OK;否则返回ERROR
if (S.top == S.base)
{
return ERROR;
}
e = *--S.top;
return OK;
}//Pop
OperandType Operate(OperandType a, SElemType theta, OperandType b)
{
switch (theta)
{
case '+': return a+b; break;
case '-': return a-b; break;
case '*': return a*b; break;
case '/': return a/b; break;
default:return ; break;
}
}
OperandType GetTop_Float(SqStack_Float S)
{
//若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;
//否则返回ERROR
if (S.top == S.base)
{
return ERROR;
}
return *(S.top - );
}//GetTop
OperandType EvaluateExpression()
{
//算数表达式求值的算符优先算法。设 OPTR 和 OPND
//分别为运算符栈和运算数栈,OP 为运算符集合
SqStack_Char OPTR;
SqStack_Float OPND;
InitStack_Char(OPTR);
Push_Char(OPTR, '#');
InitStack_Float(OPND);
char c = getchar(), x, theta;
float a, b;
while ('#' != c || GetTop_Char(OPTR) != '#')
{
//if (!In(c, OP))
if (!isInOPTR(c))
{
float temp = c-'';
Push_Float(OPND, temp);//不是运算符则进栈
c = getchar();
}
else
{
switch (Precede(GetTop_Char(OPTR), c))
{
case '<'://栈顶元素优先权低
{
Push_Char(OPTR, c);
c = getchar();
break;
}
case '='://脱括号并接收下一字符
{
Pop_Char(OPTR, x);
c = getchar();
break;
}
case '>'://退栈并将运算符结果入栈
{
Pop_Char(OPTR, theta);
Pop_Float(OPND, b);
Pop_Float(OPND, a);
Push_Float(OPND, Operate(a, theta, b));
break;
}
}
}
}
return GetTop_Float(OPND);
}
#endif

3_2_expression.h

  三.CPP文件

  迷宫求解:

 #include "3_2_maze.h"
int main(int argc, char const *argv[])
{
freopen("map.txt", "r", stdin);
printf("Map\n");
int size;
scanf("%d", &size);
MakeMap(size);
PosType start, end;
scanf("%d%d", &start.x, &start.y);
printf("start:\tx:%d\ty:%d\n", start.x, start.y);
scanf("%d%d", &end.x, &end.y);
printf("end:\tx:%d\ty:%d\n", end.x, end.y);
MazeType maze;//un useded for me
MazePath(maze, start, end, size);
//PrintPath(size);
return ;
}

3_2_maze.cpp

  表达式求值:

 #include "3_2_expression.h"
int main(int argc, char const *argv[])
{
float ans;
for (int i = ; i < ; ++i)
{
ans = EvaluateExpression();
printf("%.3f\n", ans);
}
return ;
}

3_2_expression.cpp

  四.测试

  迷宫求解:

  

  

  表达式求值:

  

  五.迷宫求解的输入文件map.txt

XXXXXXXXXX
XOOXOOOXOX
XOOXOOOXOX
XOOOOXXOOX
XOXXXOOOOX
XOOOXOOOOX
XOXOOOXOOX
XOXXXOXXOX
XXOOOOOOOX
XXXXXXXXXX

map.txt

  六.优化的表达式求值代码

  用了一些简单的C++语法(主要是为了节省代码),写了一个可以计算较复杂表达式的程序。(STL不熟,估计以后看会很蹩脚!)

 #include <iostream>
#include <string>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <map>
using namespace std;
bool isInOPTR(char ch){
switch (ch) {
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
case '#':{
return true;
break;
}
default:{
return false;
break;
}
}
}
char Precede(char a, char b){
map<char, int> myMap;
myMap['+'] = ;
myMap['-'] = ;
myMap['*'] = ;
myMap['/'] = ;
myMap['('] = ;
myMap[')'] = ;
myMap['#'] = ;
char R[][] = {{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},
{'>','>','>','>','<','>','>'},
{'<','<','<','<','<','=','#'},
{'>','>','>','>','#','>','>'},
{'<','<','<','<','<','#','='}};
if ('#' == R[myMap[a]][myMap[b]]){
printf("Precede ERROE\n");
printf("%c%c\n", a, b);
exit(-);
}
return R[myMap[a]][myMap[b]];
}
float Caculate(float a, char theta, float b){
switch (theta){
case '+':{
return a+b;
break;
}
case '-':{
return a-b;
break;
}
case '*':{
return a*b;
break;
}
case '/':{
return a/b;
}
default:{
printf("Operator ERROR\n");
exit(-);
}
}
}
void expression(void){
string Str;
getline(cin, Str);
cout <<"Your input: " + Str + '\b' + ' ' << endl;
char Operator = ' ';
float Operand = ;
stack<char> OPTR;
stack<float> OPND;
OPTR.push('#');
int i = ;
char number[];
while (Operator != '#' || OPTR.top() != '#'){
//fool code!!!
for (int k = ;i <= Str.length();){
if (isInOPTR(Str.at(i)))
{
Operator = Str.at(i++);
break;
}
else
{
number[k] = Str.at(i);
k++;
i++;
if (isInOPTR(Str.at(i)))
{
number[k] = '\0';
Operand = atof(number);
OPND.push(Operand);
continue;
} }
}
switch (Precede(OPTR.top(), Operator)){
case '<':{
OPTR.push(Operator);
break;
}
case '=':{
OPTR.pop();
break;
}
case '>':{
float a, b;
char theta;
theta = OPTR.top();
OPTR.pop();
b = OPND.top();
OPND.pop();
a = OPND.top();
OPND.pop();
OPND.push(Caculate(a, theta, b));
i--;//attention!!!!!!!
break;
}
}
}
cout << "Answer: " <<OPND.top() << endl; }
int main(int argc, char const *argv[])
{
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
for (int i = ; i < ; ++i)
{
expression();
}
return ;
}

final_expression.cpp

  测试数据:

3.2*-/+#
3.45*-(-)*#
*//#
2.22*(-)#
-#

in.txt

  结果:

Your input: 3.2*-/+
Answer: 30.05
Your input: 3.45*-(-)*
Answer:
Your input: *//
Answer:
Your input: 2.22*(-)
Answer: -
Your input: -
Answer:

out.txt

数据结构算法C语言实现(八)--- 3.2栈的应用举例:迷宫求解与表达式求值的更多相关文章

  1. 表达式求值--数据结构C语言算法实现

    这篇博客介绍的表达式求值是用C语言实现的,只使用了c++里面的引用. 数据结构课本上的一个例题,但是看起来很简单,实现却遇到了很多问题. 这个题需要构建两个栈,一个用来存储运算符OPTR, 一个用来存 ...

  2. 数据结构课程设计四则运算表达式求值(C语言版)

    本系统为四则运算表达式求值系统,用于带小括号的一定范围内正负数的四则运算标准(中缀)表达式的求值.注意事项:    1.请保证输入的四则表达式的合法性.输入的中缀表达式中只能含有英文符号"+ ...

  3. C++表达式求值(利用数据结构栈)

    唉,刚刚用C++又又一次写了一个较完好的表达式求值程序,最后精简后程序还不到100行.这不经让我 想到了大一上学期刚学c语言时自己费了好大的劲,写了几百行并且功能还不是非常齐全(当时还不能计算有括号的 ...

  4. C语言中缀表达式求值(综合)

    题前需要了解的:中缀.后缀表达式是什么?(不知道你们知不知道,反正我当时不知道,搜的百度) 基本思路:先把输入的中缀表达式→后缀表达式→进行计算得出结果 栈:"先进先出,先进后出" ...

  5. 利用栈实现算术表达式求值(Java语言描述)

    利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...

  6. 【算法】E.W.Dijkstra算术表达式求值

    算术表达式求值 我们要学习的一个栈的用例同时也是展示泛型的应用的一个经典例子,就是用来计算算术表达式的值,例如 ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) ) 如果将4乘以5,把3 ...

  7. C/C++ 语言中的表达式求值(原文作者:裘宗燕)

    经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?”m = 1; n = m+++m++;最近有位不相识的朋友发email给我,问为什么在某个C++系统里,下面表达式打印出两个4, ...

  8. Dijkstra的双栈算术表达式求值算法

    这次来复习一下Dijkstra的双栈算术表达式求值算法,其实这就是一个计算器的实现,但是这里用到了不一样的算法,同时复习了栈. 主体思想就是将每次输入的字符和数字分别存储在两个栈中.每遇到一个单次结束 ...

  9. 算法手记(2)Dijkstra双栈算术表达式求值算法

    这两天看到的内容是关于栈和队列,在栈的模块发现了Dijkstra双栈算术表达式求值算法,可以用来实现计算器类型的app. 编程语言系统一般都内置了对算术表达式的处理,但是他们是如何在内部实现的呢?为了 ...

随机推荐

  1. script实现的日期表示

    function clockon(bgclock){ var now=new Date(); var year=now.getYear(); var month=now.getMonth(); var ...

  2. TinyFrame开篇:基于CodeFirst的ORM

    前言 做项目的这段时间,由于比较忙,一直没有机会闲下来思考.正好趁目前手头活儿轻松点,就花了一两天时间搭建了一个比较简单的框架,名称暂时就叫做:TinyFrame吧.顾名思义,就是微框架的意思.虽然这 ...

  3. C“中断” 与 JS“异步回调” 横向对比

    在底层C语言中,有一个非常重要而特别的概念,叫做“中断”.用比喻来说,我正在写着博客,突然我妈打个电话过来,我就离开了键盘去接电话了,然后写博客就中断了,我聊完电话回来再继续写.乍一听似乎并没有什么大 ...

  4. Code Review 五问五答

    Code Review 是什么? Code Review即代码审查,程序猿相互审核对方的代码. Code Review能获得什么好处? 提高代码可维护性 你写的代码不再只有编译器看了,你得写出审核人能 ...

  5. MATLAB中的set函数

    1.MATLAB给每种对象的每一个属性规定了一个名字,称为属性名,而属性名的取值成为属性值.例如,LineStyle是曲线对象的一个属性名,它的值决定着线型,取值可以是'-' .':'.'-.'.'- ...

  6. 【抄】更改eclipse配置

    序言:网上流传着eclipse更改代码提示的一种方法,在eclipse IDE可视化界面没法更改一些东西,比如content assist auto activition trigger在js里面只允 ...

  7. C# Rotating Oval

    This program is used to show how to generate an oval. The moon's orbit around the sun is an oval two ...

  8. SQL-Server下载地址

    有同学费尽心思的找SQL server数据库各版本的下载地址,看到别人的求助贴就不自觉的想去帮助他们,但是一个一个去帮助又不太现实,毕竟个人精力有限,既然大家有需求,那么艾薇百科今天就本着乐于分享和奉 ...

  9. springMvc全局异常处理

    本文中只测试了:实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器 对已有代码没有入侵性等优点,同时,在异常处理时能获取导致出现异常的对象,有利于提 ...

  10. js实现倒计时效果

    <!DOCTYPE html><head><meta http-equiv="Content-Type" content="text/htm ...