数据结构——栈的应用举例

本文所有代码均为伪码,仅阐述算法基本思想——《数据结构》清华大学出版社

- 算法1
对于输入的任意一个非负十进制整数,打印输出与其等值的N进制数

 #define N 8 // 定义待转换的进制N(2~9)
 typedef int SElemType; // 定义栈元素类型为整型

 void conversion()
 { 
   SqStack s;
   unsigned n; // 非负整数
   SElemType e;
   InitStack(s); // 初始化栈
   printf("将十进制整数n转换为%d进制数,请输入:n(≥0)=",N);
   scanf("%u",&n); // 输入非负十进制整数n
   while(n) // 当n不等于0
   { Push(s,n%N); // 入栈n除以N的余数(N进制的低位)
     n=n/N;
   }
   while(!StackEmpty(s)) // 当栈不空
   { Pop(s,e); // 弹出栈顶元素且赋值给e
     printf("%d",e); // 输出e
   }
   printf("\n");
 }

- 算法2
利用字符栈s,从终端接收一行并送至调用过程的数据区。

 typedef char SElemType; // 定义栈元素类型为字符型
 #include"c1.h"
 FILE *fp;

 void copy(SElemType c)
 { // 将字符c送至fp所指的文件中
   fputc(c,fp);
 }

 void LineEdit()
 { 
   SqStack s;
   char ch;
   InitStack(s); // 初始化栈s
   printf("请输入一个文本文件,^Z结束输入:\n");
   ch=getchar(); // 接收字符到ch
   while(ch!=EOF) // 当全文未结束(EOF为^Z键,全文结束符)
   { while(ch!=EOF&&ch!='\n') // 当全文未结束且未到行末(不是换行符)
     { switch(ch) // 对于当前字符ch,分情况处理
       { case '#':if(!StackEmpty(s))
                    Pop(s,ch); // 仅当栈非空时弹出栈顶元素,c可由ch替代
                  break;
         case '@':ClearStack(s); // 重置s为空栈
                  break;
         default :Push(s,ch); // 其他字符进栈
       }
       ch=getchar(); // 从终端接收下一个字符到ch
     } // 到行末或全文结束,退出此层循环
     StackTraverse(s,copy); // 将从栈底到栈顶的栈内字符依次传送至文件(调用copy()函数)
     fputc('\n',fp); // 向文件输入一个换行符
     ClearStack(s); // 重置s为空栈
     if(ch!=EOF) // 全文未结束
       ch=getchar(); // 从终端接收下一个字符到ch
   }
   DestroyStack(s); // 销毁栈s
 }

- 算法3
利用栈求解迷宫问题

 struct PosType // 迷宫坐标位置类型
 { int x; // 行值
   int y; // 列值
 };
 // 全局变量
 PosType begin,end; // 迷宫的入口坐标,出口坐标
 PosType direc[4]={{0,1},{1,0},{0,-1},{-1,0}};
 // {行增量,列增量},移动方向依次为东南西北

 #define MAXLENGTH 25 // 设迷宫的最大行列为25
 typedef int MazeType[MAXLENGTH][MAXLENGTH]; // 迷宫数组类型[行][列]
 MazeType m; // 迷宫数组
 int x,y; // 迷宫的行数,列数

 void Print()
 { // 输出迷宫的解(m数组)
   int i,j;
   for(i=0;i<x;i++)
   { for(j=0;j<y;j++)
       printf("%3d",m[i][j]);
     printf("\n");
   }
 }

 void Init()
 { // 设定迷宫布局(墙值为0,通道值为1)
   int i,j,x1,y1;
   printf("请输入迷宫的行数,列数(包括外墙):");
   scanf("%d,%d",&x,&y);
   for(i=0;i<y;i++) // 定义周边值为0(外墙)
   { m[0][i]=0; // 上边
     m[x-1][i]=0; // 下边
   }
   for(i=1;i<x-1;i++)
   { m[i][0]=0; // 左边
     m[i][y-1]=0; // 右边
   }
   for(i=1;i<x-1;i++)
     for(j=1;j<y-1;j++)
       m[i][j]=1; // 定义除外墙,其余都是通道,初值为1
   printf("请输入迷宫内墙单元数:");
   scanf("%d",&j);
   printf("请依次输入迷宫内墙每个单元的行数,列数:\n");
   for(i=1;i<=j;i++)
   { scanf("%d,%d",&x1,&y1);
     m[x1][y1]=0; // 修改内墙的值为0
   }
   printf("迷宫结构如下:\n");
   Print();
   printf("请输入入口的行数,列数:");
   scanf("%d,%d",&begin.x,&begin.y);
   printf("请输入出口的行数,列数:");
   scanf("%d,%d",&end.x,&end.y);
 }

 int curstep=1; // 当前足迹,初值(在入口处)为1
 struct SElemType // 栈的元素类型。在教科书第51页
 { int ord; // 通道块在路径上的“序号”
   PosType seat; // 通道块在迷宫中的“坐标位置”
   int di; // 从此通道块走向下一通道块的“方向”(0~3表示东~北)
 };

 // 定义墙元素值为0,可通过路径为1,经试探不可通过路径为-1,通过路径为足迹
 Status Pass(PosType b)
 { // 当迷宫m的b点的值为1(可通过路径),返回OK;否则,返回ERROR
   if(m[b.x][b.y]==1)
     return OK;
   else
     return ERROR;
 }

 void FootPrint(PosType b)
 { // 使迷宫m的b点的值变为足迹(curstep)
   m[b.x][b.y]=curstep;
 }

 void NextPos(PosType &b,int di)
 { // 根据当前位置b及移动方向di,修改b为下一位置
   b.x+=direc[di].x;
   b.y+=direc[di].y;
 }

 void MarkPrint(PosType b)
 { // 使迷宫m的b点的值变为-1(标记为经试探由此不能到达终点的路径)
   m[b.x][b.y]=-1;
 }

 Status MazePath(PosType start,PosType end) 
 { // 若迷宫m中存在从入口start到出口end的通道,则求得一条存放在栈中(从栈底到栈顶),
   // 并返回TRUE;否则返回FALSE
   PosType curpos=start; // 当前位置在入口
   SqStack S; // 顺序栈
   SElemType e; // 栈元素
   InitStack(S); // 初始化栈
   do
   { if(Pass(curpos)) // 当前位置可以通过,即是未曾走到过的通道块
     { FootPrint(curpos); // 留下足迹(使迷宫m的当前位置的值为curstep)
       e.ord=curstep; // 栈元素的序号为当前足迹curstep
       e.seat=curpos; // 栈元素的位置为当前位置
       e.di=0; // 从当前位置出发,下一位置是向东
       Push(S,e); // 入栈当前位置及状态
       curstep++; // 足迹加1
       if(curpos.x==end.x&&curpos.y==end.y) // 到达终点(出口)
         return TRUE;
       NextPos(curpos,e.di); // 由当前位置及移动方向,确定下一个当前位置,仍赋给curpos
     }
     else // 当前位置不能通过
     { if(!StackEmpty(S)) // 栈不空
       { Pop(S,e); // 退栈到前一位置
         curstep--; // 足迹减1
         while(e.di==3&&!StackEmpty(S)) // 前一位置处于最后一个方向(北)且栈不空
         { MarkPrint(e.seat); // 在前一位置留下由其不能到达终点的标记(-1)
           Pop(S,e); // 再退回一步
           curstep--; // 足迹再减1
         }
         if(e.di<3) // 未到最后一个方向(北)
         { e.di++; // 换下一个方向探索
           Push(S,e); // 入栈该位置的下一个方向
           curstep++; // 足迹加1
           curpos=e.seat; // 确定当前位置
           NextPos(curpos,e.di); // 由当前位置及移动方向,确定下一个当前位置,仍赋给curpos
         }
       }
     }
   }while(!StackEmpty(S));
   return FALSE;
 }

- 算法4
表达式求值(输入的值在0~9之间,中间结果和输出的值在-128~127之间)

 typedef char SElemType; // 定义栈元素为字符型

 SElemType EvaluateExpression()
 { // 算术表达式求值的算符优先算法。设OPTR和OPND分别为运算符栈和运算数栈
   SqStack OPTR,OPND;
   SElemType a,b,c,x;
   InitStack(OPTR); // 初始化运算符栈OPTR和运算数栈OPND
   InitStack(OPND);
   Push(OPTR,'\n'); // 将换行符压入运算符栈OPTR的栈底。修改
   c=getchar(); // 由键盘读入1个字符到c
   GetTop(OPTR,x); // 将运算符栈OPTR的栈顶元素赋给x
   while(c!='\n'||x!='\n') // c和x不都是换行符
   { if(In(c)) // c是7种运算符之一
       switch(Precede(x,c)) // 判断x和c的优先权
       { case'<':Push(OPTR,c); // 运算符栈OPTR的栈顶元素x的优先权低,入栈c
                 c=getchar(); // 由键盘读入下一个字符到c
                 break;
         case'=':Pop(OPTR,x); // x='('且c=')'情况,弹出'('给x(后又扔掉)
                 c=getchar(); // 由键盘读入下一个字符到c(扔掉c原有的')')
                 break;
         case'>':Pop(OPTR,x); // 栈顶元素x的优先权高,弹出运算符栈OPTR的栈顶元素给x。修改
                 Pop(OPND,b); // 依次弹出运算数栈OPND的栈顶元素给b,a
                 Pop(OPND,a);
                 Push(OPND,Operate(a,x,b)); // 做运算a x b,并将运算结果入运算数栈
       }
     else if(c>='0'&&c<='9') // c是操作数
     { Push(OPND,c-48); // 将该操作数的值(不是ASCII码)压入运算数栈OPND
       c=getchar(); // 由键盘读入下一个字符到c
     }
     else // c是非法字符
     { printf("出现非法字符\n");
       exit(OVERFLOW);
     }
     GetTop(OPTR,x); // 将运算符栈OPTR的栈顶元素赋给x
   }
   Pop(OPND,x); // 弹出运算数栈OPND的栈顶元素(运算结果)给x(修改此处)
   if(!StackEmpty(OPND)) // 运算数栈OPND不空(运算符栈OPTR仅剩'\n')
   { printf("表达式不正确\n");
     exit(OVERFLOW);
   }
   return x;
 }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值