Fork me on GitHub

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

  一.简介

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

  表达式求值:

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

  二.头文件

  迷宫求解:

  1 //3_2_maze.h
  2 /**
  3 author:zhaoyu
  4 email:zhaoyu1995.com@gmail.com
  5 date:2016-6-8
  6 note:realize my textbook <<数据结构(C语言版)>>
  7 */
  8 //Page 51
  9 #ifndef _3_2_MAZE_H
 10 #define _3_2_MAZE_H 
 11 #include <cstdio>
 12 #include <cstdlib>
 13 #include <cstring>
 14 #include "head.h"
 15 #define STACK_INIT_SIZE 200//存储空间的初始分配值
 16 #define STACKINCREMENT 10//存储空间分配增量
 17 #define WALL -1
 18 #define PATH 1
 19 #define PASSED -2
 20 #define UNREACHABLE -3 
 21 #define FINALPATH -4 
 22 #define NMAX 50
 23 char Map[NMAX][NMAX];
 24 typedef struct{
 25     int x;
 26     int y;
 27 }PosType;
 28 typedef struct node_1{
 29     int x, y;
 30     struct node_1 *next;
 31 }MazeType;
 32 typedef struct{
 33     int ord;//通道块在路径上的序号
 34     PosType seat;//通道块在迷宫中的位置
 35     int direction;//从此通道块走向下一通道块的方向
 36 }SElemType;
 37 typedef struct{
 38     SElemType *base;//在栈构造之前和销毁之后,base 值为 NULL
 39     SElemType *top;//栈顶指针
 40     int stacksize;//当前已分配的存储空间,以元素为单位
 41 }SqStack;
 42 Status InitStack(SqStack &S)
 43 {
 44     //构造一个空栈 S
 45     S.base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
 46     if (!S.base)
 47     {
 48         exit(OVERFLOW);
 49     }
 50     S.top = S.base;
 51     S.stacksize = STACK_INIT_SIZE;
 52     return OK;
 53 }//InitStack
 54 void Assign_PosType(PosType &a, PosType b)
 55 {
 56     a.x = b.x;
 57     a.y = b.y;
 58 }//Assign_PosType
 59 Status Pass(PosType pos)
 60 {//可能写的不对,注意
 61     if (PATH == Map[pos.x][pos.y])
 62     {
 63         return TRUE;
 64     }
 65     else
 66     {
 67         return FALSE;
 68     }
 69 }//Pass
 70 void FoorPrint(PosType pos)
 71 {
 72     Map[pos.x][pos.y] = PASSED;
 73 }
 74 void Assign_SELemType(SElemType &e, int x, PosType pos, int y)
 75 {
 76     e.ord = x;
 77     Assign_PosType(e.seat, pos);
 78     e.direction = y;
 79 }
 80 Status Push(SqStack &S, SElemType e)
 81 {
 82     //插入元素 e 为新的栈顶元素
 83     if (S.top - S.base >= S.stacksize)
 84     {//栈满,追加存储空间
 85         S.base = (SElemType *)realloc(S.base,
 86             (S.stacksize+STACKINCREMENT)*sizeof(SElemType));
 87         if (!S.base)
 88         {
 89             exit(OVERFLOW);
 90         }
 91         S.top = S.base + S.stacksize;
 92         S.stacksize += STACKINCREMENT;
 93     }
 94     //*S.top++ = e;
 95     Assign_SELemType(*S.top++, e.ord, e.seat, e.direction);
 96     return OK;
 97 }//Push
 98 PosType NextPos(PosType pos, int direction)
 99 {
100     PosType temp;
101     switch (direction)
102     {
103         case 1:
104         {
105             temp.x = pos.x;
106             temp.y = pos.y+1;
107             break;
108         }
109         case 2:
110         {
111             temp.x = pos.x + 1;
112             temp.y = pos.y;
113             break;
114         }
115         case 3:
116         {
117             temp.x = pos.x;
118             temp.y = pos.y - 1;
119             break;
120         }
121         case 4:
122         {
123             temp.x = pos.x - 1;
124             temp.y = pos.y;
125             break;
126         }
127     }
128     //加一个越界检查
129     return temp;
130 }
131 Status StackEmpty(SqStack S)
132 {
133     //若 S 为空栈, 则返回 TRUE, 否则返回 FALSE
134     if (S.base == S.top)
135     {
136         return TRUE;
137     }
138     else
139     {
140         return FALSE;
141     }
142 }
143 Status Pop(SqStack &S, SElemType &e)
144 {
145     //若栈不空,则删除 S 的栈顶元素,用 e 返回其
146     //值,并返回OK;否则返回ERROR
147     if (S.top == S.base)
148     {
149         return ERROR;
150     }
151     //e = *--S.top;
152     S.top--;
153     Assign_SELemType(e, (*S.top).ord, (*S.top).seat, (*S.top).direction);
154     return OK;
155 }//Pop
156 void FootPrint(PosType pos)
157 {
158     Map[pos.x][pos.y] = PASSED;    
159 }
160 void MarkPrint(PosType pos)
161 {
162     Map[pos.x][pos.y] = UNREACHABLE;
163 }
164 void MakeMap(int size)
165 {
166     memset(Map, 0, sizeof(Map));
167     char ch;
168     getchar();
169     for (int i = 1; i <= size; i++)
170     {
171         for (int j = 1; j <= size; j++)
172         {
173             scanf("%c", &ch);
174             if ('X' == ch)
175             {
176                 Map[i][j] = UNREACHABLE;
177             }
178             else
179             {
180                 Map[i][j] = PATH;
181             }
182         }
183         //attention '\n'
184         getchar();
185     }
186     //Print maze
187     for (int i = 1; i <= size; i++)
188     {
189         for (int j = 1; j <= size; j++)
190         {
191             if (UNREACHABLE == Map[i][j])
192             {
193                 printf("X");
194             }
195             else
196             {
197                 printf(" ");
198             }
199         }
200         printf("\n");
201     }
202 }
203 void PrintPath(SqStack S, int size)
204 {
205     SElemType e;
206     SqStack temp;
207     while (!StackEmpty(S))
208     {
209         Pop(S, e);
210         Map[e.seat.x][e.seat.y] = FINALPATH;
211     }
212     for (int i = 1; i <= size; i++)
213     {
214         for (int j = 1; j <= size; j++)
215         {
216             if (UNREACHABLE == Map[i][j])
217             {
218                 printf("X");
219             }
220             else if (FINALPATH == Map[i][j])
221             {
222                 printf("O");
223             }
224             else
225             {
226                 printf(" ");
227             }
228         }
229         printf("\n");
230     }
231 }
232 Status MazePath(MazeType maze, PosType start, PosType end, int size)
233 {
234     //若迷宫 maze 中存在从入口 start 到出口 end 的通道,
235     //则求得一条存放在栈中(从栈底到栈顶),并返回 TRUE,
236     //否则返回 FALSE
237     SqStack S;
238     InitStack(S);
239     //curpos = start
240     PosType curpos;
241     Assign_PosType(curpos, start);//设定当前位置为入口位置
242     int curstep = 1;//探索第一步
243     SElemType e;
244     do{
245         if (TRUE == Pass(curpos))
246         {//当前位置可以通过
247             FootPrint(curpos);//留下足迹
248             //e = (curstep, curpos, 1);
249             Assign_SELemType(e, curstep, curpos, 1);
250             Push(S, e);//加入路径
251             if (curpos.x == end.x && curpos.y == end.y)
252             {
253                 //打印路径
254                 printf("PATH EXIST\n");
255                 PrintPath(S ,size);
256                 return TRUE;
257             }
258             curpos = NextPos(curpos, 1);//下一位置是当前位置的东邻
259             curstep++;//探索下一步
260         }
261         else
262         {
263             if (!StackEmpty(S))
264             {
265                 Pop(S, e);
266                 while (4 == e.direction && !StackEmpty(S))
267                 {
268                     MarkPrint(e.seat);
269                     Pop(S, e);//留下不能通过的标记,并退回一步
270                 }
271                 if (e.direction < 4)
272                 {
273                     e.direction++;
274                     Push(S, e);
275                     curpos = NextPos(e.seat, e.direction);
276                 }
277             }
278         }
279     }while (!StackEmpty(S));
280 
281 }
282 #endif
3_2_maze.h

  表达式求值:

  1 //3_2_maze.h
  2 /**
  3 author:zhaoyu
  4 email:zhaoyu1995.com@gmail.com
  5 date:2016-6-8
  6 note:realize my textbook <<数据结构(C语言版)>>
  7 */
  8 //Page 53
  9 #ifndef _3_2_EXPRESSION_H_
 10 #define _3_2_EXPRESSION_H_
 11 #include "head.h"
 12 
 13 #define SElemType char
 14 #define OperandType float
 15 #define STACK_INIT_SIZE 100//存储空间的初始分配值
 16 #define STACKINCREMENT 10//存储空间分配增量
 17 typedef struct{
 18     SElemType *base;//在栈构造之前和销毁之后,base 值为 NULL
 19     SElemType *top;//栈顶指针
 20     int stacksize;//当前已分配的存储空间,以元素为单位
 21 }SqStack_Char;
 22 typedef struct{
 23     OperandType *base;//在栈构造之前和销毁之后,base 值为 NULL
 24     OperandType *top;//栈顶指针
 25     int stacksize;//当前已分配的存储空间,以元素为单位
 26 }SqStack_Float;
 27 Status InitStack_Char(SqStack_Char &S)
 28 {
 29     //构造一个空栈 S
 30     S.base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
 31     if (!S.base)
 32     {
 33         exit(OVERFLOW);
 34     }
 35     S.top = S.base;
 36     S.stacksize = STACK_INIT_SIZE;
 37     return OK;
 38 }//InitStack
 39 Status InitStack_Float(SqStack_Float &S)
 40 {
 41     //构造一个空栈 S
 42     S.base = (OperandType *)malloc(STACK_INIT_SIZE*sizeof(OperandType));
 43     if (!S.base)
 44     {
 45         exit(OVERFLOW);
 46     }
 47     S.top = S.base;
 48     S.stacksize = STACK_INIT_SIZE;
 49     return OK;
 50 }//InitStack
 51 Status Push_Char(SqStack_Char &S, SElemType e)
 52 {
 53     //插入元素 e 为新的栈顶元素
 54     if (S.top - S.base >= S.stacksize)
 55     {//栈满,追加存储空间
 56         S.base = (SElemType *)realloc(S.base,
 57             (S.stacksize+STACKINCREMENT)*sizeof(SElemType));
 58         if (!S.base)
 59         {
 60             exit(OVERFLOW);
 61         }
 62         S.top = S.base + S.stacksize;
 63         S.stacksize += STACKINCREMENT;
 64     }
 65     *S.top++ = e;
 66     return OK;
 67 }//Push
 68 SElemType GetTop_Char(SqStack_Char S)
 69 {
 70     //若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;
 71     //否则返回ERROR
 72     if (S.top == S.base)
 73     {
 74         return ERROR;
 75     }
 76     return *(S.top - 1);
 77 }//GetTop
 78 Status isInOPTR(SElemType c)
 79 {
 80     switch (c)
 81     {
 82         case '+':
 83         case '-':
 84         case '*':
 85         case '/':
 86         case '(':
 87         case ')':
 88         case '#':
 89         {
 90             return TRUE;
 91             break;
 92         }
 93         default:
 94         {
 95             return FALSE;
 96             break;
 97         }
 98     }
 99 }
100 Status Push_Float(SqStack_Float &S, OperandType e)
101 {
102     //插入元素 e 为新的栈顶元素
103     if (S.top - S.base >= S.stacksize)
104     {//栈满,追加存储空间
105         S.base = (OperandType *)realloc(S.base,
106             (S.stacksize+STACKINCREMENT)*sizeof(OperandType));
107         if (!S.base)
108         {
109             exit(OVERFLOW);
110         }
111         S.top = S.base + S.stacksize;
112         S.stacksize += STACKINCREMENT;
113     }
114     *S.top++ = e;
115     return OK;
116 }//Push
117 char Precede(SElemType a, SElemType b)
118 {
119     char R[7][7] =  {{'>','>','<','<','<','>','>'},
120                     {'>','>','<','<','<','>','>'},
121                     {'>','>','>','>','<','>','>'},
122                     {'>','>','>','>','<','>','>'},
123                     {'<','<','<','<','<','=','#'},
124                     {'>','>','>','>','#','>','>'},
125                     {'<','<','<','<','<','#','='}};
126     int i,j;
127     switch (a)
128     {
129         case '+':i=0;break;
130         case '-':i=1;break;
131         case '*':i=2;break;
132         case '/':i=3;break;
133         case '(':i=4;break;
134         case ')':i=5;break;
135         case '#':i=6;break;
136         default:i=0;break;
137     }
138     switch (b)
139     {
140         case '+':j=0;break;
141         case '-':j=1;break;
142         case '*':j=2;break;
143         case '/':j=3;break;
144         case '(':j=4;break;
145         case ')':j=5;break;
146         case '#':j=6;break;
147         default:j=0;break;
148     }
149     if ('#' == R[i][j])
150     {
151         printf("ERROR\n");
152         exit(ERROR);
153     }
154     else
155     {
156         return R[i][j];
157     }
158 }
159 Status Pop_Char(SqStack_Char &S, SElemType &e)
160 {
161     //若栈不空,则删除 S 的栈顶元素,用 e 返回其
162     //值,并返回OK;否则返回ERROR
163     if (S.top == S.base)
164     {
165         return ERROR;
166     }
167     e = *--S.top;
168     return OK;
169 }//Pop
170 Status Pop_Float(SqStack_Float &S, OperandType &e)
171 {
172     //若栈不空,则删除 S 的栈顶元素,用 e 返回其
173     //值,并返回OK;否则返回ERROR
174     if (S.top == S.base)
175     {
176         return ERROR;
177     }
178     e = *--S.top;
179     return OK;
180 }//Pop
181 OperandType Operate(OperandType a, SElemType theta, OperandType b)
182 {
183     switch (theta)
184     {
185         case '+': return a+b; break;
186         case '-': return a-b; break;
187         case '*': return a*b; break;
188         case '/': return a/b; break;
189         default:return 0; break;
190     }
191 }
192 OperandType GetTop_Float(SqStack_Float S)
193 {
194     //若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;
195     //否则返回ERROR
196     if (S.top == S.base)
197     {
198         return ERROR;
199     }
200     return *(S.top - 1);
201 }//GetTop
202 OperandType EvaluateExpression()
203 {
204     //算数表达式求值的算符优先算法。设 OPTR 和 OPND 
205     //分别为运算符栈和运算数栈,OP 为运算符集合
206     SqStack_Char OPTR;
207     SqStack_Float OPND;
208     InitStack_Char(OPTR);
209     Push_Char(OPTR, '#');
210     InitStack_Float(OPND);
211     char c = getchar(), x, theta;
212     float a, b;
213     while ('#' != c || GetTop_Char(OPTR) != '#')
214     {
215         //if (!In(c, OP))
216         if (!isInOPTR(c))
217         {
218             float temp = c-'0';
219             Push_Float(OPND, temp);//不是运算符则进栈
220             c = getchar();
221         }
222         else
223         {
224             switch (Precede(GetTop_Char(OPTR), c))
225             {
226                 case '<'://栈顶元素优先权低
227                 {
228                     Push_Char(OPTR, c);
229                     c = getchar();
230                     break;
231                 }
232                 case '='://脱括号并接收下一字符
233                 {
234                     Pop_Char(OPTR, x);
235                     c = getchar();
236                     break;
237                 }
238                 case '>'://退栈并将运算符结果入栈
239                 {
240                     Pop_Char(OPTR, theta);
241                     Pop_Float(OPND, b);
242                     Pop_Float(OPND, a);
243                     Push_Float(OPND, Operate(a, theta, b));
244                     break;
245                 }
246             }
247         }
248     }
249     return GetTop_Float(OPND);
250 }
251 #endif
3_2_expression.h

  三.CPP文件

  迷宫求解:

 1 #include "3_2_maze.h"
 2 int main(int argc, char const *argv[])
 3 {
 4     freopen("map.txt", "r", stdin);
 5     printf("Map\n");
 6     int size;
 7     scanf("%d", &size);
 8     MakeMap(size);
 9     PosType start, end;
10     scanf("%d%d", &start.x, &start.y);
11     printf("start:\tx:%d\ty:%d\n", start.x, start.y);
12     scanf("%d%d", &end.x, &end.y);
13     printf("end:\tx:%d\ty:%d\n", end.x, end.y);
14     MazeType maze;//un useded for me
15     MazePath(maze, start, end, size);
16     //PrintPath(size);
17     return 0;
18 }
3_2_maze.cpp

  表达式求值:

 1 #include "3_2_expression.h"
 2 int main(int argc, char const *argv[])
 3 {
 4     float ans;
 5     for (int i = 0; i < 5; ++i)
 6     {
 7         ans = EvaluateExpression();
 8         printf("%.3f\n", ans);
 9     }
10     return 0;
11 }
3_2_expression.cpp

  四.测试

  迷宫求解:

  

  

  表达式求值:

   

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

10
XXXXXXXXXX
XOOXOOOXOX
XOOXOOOXOX
XOOOOXXOOX
XOXXXOOOOX
XOOOXOOOOX
XOXOOOXOOX
XOXXXOXXOX
XXOOOOOOOX
XXXXXXXXXX
2
2
9
9
map.txt

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

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

  1 #include <iostream>
  2 #include <string>
  3 #include <stack>
  4 #include <cstdio>
  5 #include <cstdlib>
  6 #include <map>
  7 using namespace std;
  8 bool isInOPTR(char ch){
  9     switch (ch)    {
 10         case '+':
 11         case '-':
 12         case '*':
 13         case '/':
 14         case '(':
 15         case ')':
 16         case '#':{
 17             return true;
 18             break;
 19         }
 20         default:{
 21             return false;
 22             break;
 23         }
 24     }
 25 }
 26 char Precede(char a, char b){
 27     map<char, int> myMap;
 28     myMap['+'] = 0;
 29     myMap['-'] = 1;
 30     myMap['*'] = 2;
 31     myMap['/'] = 3;
 32     myMap['('] = 4;
 33     myMap[')'] = 5;
 34     myMap['#'] = 6;
 35     char R[7][7] =  {{'>','>','<','<','<','>','>'},
 36                     {'>','>','<','<','<','>','>'},
 37                     {'>','>','>','>','<','>','>'},
 38                     {'>','>','>','>','<','>','>'},
 39                     {'<','<','<','<','<','=','#'},
 40                     {'>','>','>','>','#','>','>'},
 41                     {'<','<','<','<','<','#','='}};
 42     if ('#' == R[myMap[a]][myMap[b]]){
 43         printf("Precede ERROE\n");
 44         printf("%c%c\n", a, b);
 45         exit(-1);
 46     }
 47     return R[myMap[a]][myMap[b]];
 48 }
 49 float Caculate(float a, char theta, float b){
 50     switch (theta){
 51         case '+':{
 52             return a+b;
 53             break;
 54         }
 55         case '-':{
 56             return a-b;
 57             break;
 58         }
 59         case '*':{
 60             return a*b;
 61             break;
 62         }
 63         case '/':{
 64             return a/b;
 65         }
 66         default:{
 67             printf("Operator ERROR\n");
 68             exit(-1);
 69         }
 70     }
 71 }
 72 void expression(void){
 73     string Str;
 74     getline(cin, Str);
 75     cout <<"Your input: " + Str + '\b' + ' ' << endl;
 76     char Operator = ' ';
 77     float Operand = 0;
 78     stack<char> OPTR;
 79     stack<float> OPND;
 80     OPTR.push('#');
 81     int i = 0;
 82     char number[20];
 83     while (Operator != '#' || OPTR.top() != '#'){
 84         //fool code!!!
 85         for (int k = 0;i <= Str.length();){
 86             if (isInOPTR(Str.at(i)))
 87             {
 88                 Operator = Str.at(i++);
 89                 break;
 90             }
 91             else
 92             {
 93                 number[k] = Str.at(i);
 94                 k++;
 95                 i++;
 96                 if (isInOPTR(Str.at(i)))
 97                 {
 98                     number[k] = '\0';
 99                     Operand = atof(number);
100                     OPND.push(Operand);
101                     continue;
102                 }
103 
104             }
105         }
106         switch (Precede(OPTR.top(), Operator)){
107             case '<':{
108                 OPTR.push(Operator);
109                 break;
110             }
111             case '=':{
112                 OPTR.pop();
113                 break;
114             }
115             case '>':{
116                 float a, b;
117                 char theta;
118                 theta = OPTR.top();
119                 OPTR.pop();
120                 b = OPND.top();
121                 OPND.pop();
122                 a = OPND.top();
123                 OPND.pop();
124                 OPND.push(Caculate(a, theta, b));
125                 i--;//attention!!!!!!!
126                 break;
127             }
128         }
129     }
130     cout << "Answer: " <<OPND.top() << endl;
131 
132 }
133 int main(int argc, char const *argv[])
134 {
135     freopen("in.txt", "r", stdin);
136     freopen("out.txt", "w", stdout);
137     for (int i = 0; i < 5; ++i)
138     {
139         expression();
140     }
141     return 0;
142 }
final_expression.cpp

  测试数据:

3.2*9-3/4+2#
3.45*100-(10-4)*5#
3*3/3/3#
2.22*(10-110)#
1-1#
in.txt

  结果:

Your input: 3.2*9-3/4+2
Answer: 30.05
Your input: 3.45*100-(10-4)*5
Answer: 315
Your input: 3*3/3/3
Answer: 1
Your input: 2.22*(10-110)
Answer: -222
Your input: 1-1
Answer: 0
out.txt

 

posted @ 2016-06-08 22:09  赵裕(vimerzhao)  阅读(1879)  评论(0编辑  收藏  举报