栈的应用

来源:互联网 发布:武汉天融信网络 编辑:程序博客网 时间:2024/06/05 16:24
 1、数制转换
         十进制数N和其他d进制数的转换。
         原理:N=(N div d)*d+N mod d (其中:div为整除运算,mod为求余运算)
         具体例题:
         对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数。
         思想:
         在计算过程中,是从低位到高位的顺序产生八进制数的各个位数,而打印输出则是从高位到低位进行,恰好与计算过程相反。在这个例子里,利用栈的后进先出特性,且操作的顺序直线式的,即先一味地进栈,再一味地出栈。
         算法:
 void conversion(  ) {       initstack(s);        scanf (“%”,n);        while(n){             push(s,n%8);             n=n/8;         }         while(! Stackempty(s)){            pop(s,e);            printf(“%d”,e);          }        }

具体代码实现(C)
 #include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<process.h> /* exit() */#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */#define STACKINCREMENT 2 /* 存储空间分配增量 */typedef struct SqStack{   int *base; /* 在栈构造之前和销毁之后,base的值为NULL */   int *top; /* 栈顶指针 */   int stacksize; /* 当前已分配的存储空间,以元素为单位 */}SqStack; /* 顺序栈 */int InitStack(SqStack *S){ /* 构造一个空栈S */   (*S).base=(int *)malloc(STACK_INIT_SIZE*sizeof(int));   if(!(*S).base)     exit(-2); /* 存储分配失败 */   (*S).top=(*S).base;   (*S).stacksize=STACK_INIT_SIZE;   return 1;}int StackEmpty(SqStack S){ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */   if(S.top==S.base)     return 1;   else     return 0;}int Push(SqStack *S,int e){ /* 插入元素e为新的栈顶元素 */   if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */   {     (*S).base=(int *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(int));     if(!(*S).base)       exit(-2); /* 存储分配失败 */     (*S).top=(*S).base+(*S).stacksize;     (*S).stacksize+=STACKINCREMENT;   }   *((*S).top)++=e;   return 1;}int Pop(SqStack *S,int *e){ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */   if((*S).top==(*S).base)     return 0;   *e=*--(*S).top;   return 1;}void conversion(){ /* 对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数 */   SqStack s;   unsigned n; /* 非负整数 */   int e;   InitStack(&s); /* 初始化栈 */   printf("n(>=0)=");   scanf("%u",&n); /* 输入非负十进制整数n */   while(n) /* 当n不等于0 */   {     Push(&s,n%8); /* 入栈n除以8的余数(8进制的低位) */     n=n/8;   }   while(!StackEmpty(s)) /* 当栈不空 */   {     Pop(&s,&e); /* 弹出栈顶元素且赋值给e */     printf("%d",e); /* 输出e */   }   printf("\n");}void main(){   conversion();}

2、括号匹配的检验
    假设表达式中允许包含两种括号:圆括号和方括号,其嵌套的顺序随意,即([]())或[([][])]等为正确的格式,[(])或([())均为不正确的格式。
    原理:设置一个栈,每读入一个括号,若是右括号,则或者使置于栈顶的最急迫的期待得以消解,或者是不合法的情况;若是左括号,则作为一个新的更急迫的期待压入栈中,自然使原有的在栈中的所有未消解的期待的急迫性都降一级。算法开始和结束时,栈都应该是空的。
  算法:
void check(){     if(InitStack(S))     {        gets(ch);        p=ch;        while(*p)          switch(*p)          {             case '(':             case '[':Push(S,*p++);break;             case ')':             case ']':if(!StackEmpty(S))                      {                         Pop(S,e);                         if(*p==')'&&e!='('||*p==']'&&e!='[')                            exit(ERROR);                         else {p++;break;}                       }                       else  exit(ERROR);            default : p++;           }      }

   具体代码的实现(C):
 #include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<process.h> /* exit() */#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */#define STACKINCREMENT 2 /* 存储空间分配增量 */typedef struct SqStack{   char *base; /* 在栈构造之前和销毁之后,base的值为NULL */   char *top; /* 栈顶指针 */   int stacksize; /* 当前已分配的存储空间,以元素为单位 */}SqStack; /* 顺序栈 */int InitStack(SqStack *S){ /* 构造一个空栈S */   (*S).base=(char *)malloc(STACK_INIT_SIZE*sizeof(char));   if(!(*S).base)     exit(-2); /* 存储分配失败 */   (*S).top=(*S).base;   (*S).stacksize=STACK_INIT_SIZE;   return 1;}int StackEmpty(SqStack S){ /* 若栈S为空栈,则返回1,否则返回0 */   if(S.top==S.base)     return 1;   else     return 0;}int Push(SqStack *S,char e){ /* 插入元素e为新的栈顶元素 */   if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */   {     (*S).base=(char *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(char));     if(!(*S).base)       exit(-2); /* 存储分配失败 */     (*S).top=(*S).base+(*S).stacksize;     (*S).stacksize+=STACKINCREMENT;   }   *((*S).top)++=e;   return 1;}int Pop(SqStack *S,char *e){ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */   if((*S).top==(*S).base)     return 0;   *e=*--(*S).top;   return 1;}void check(){ /* 对于输入的任意一个字符串,检验括号是否配对 */   SqStack s;   char ch[80],*p,e;   if(InitStack(&s)) /* 初始化栈成功 */   {     printf("请输入表达式\n");     gets(ch);     p=ch;     while(*p) /* 没到串尾 */       switch(*p)       {         case '(':         case '[':Push(&s,*p++);                  break; /* 左括号入栈,且p++ */         case ')':         case ']':if(!StackEmpty(s)) /* 栈不空 */                  {                    Pop(&s,&e); /* 弹出栈顶元素 */                    if(*p==')'&&e!='('||*p==']'&&e!='[') /* 弹出的栈顶元素与*p不配对 */                    {                      printf("左右括号不配对\n");                      exit(0);                    }                    else                    {                      p++;                      break; /* 跳出switch语句 */                    }                  }                  else /* 栈空 */                  {                    printf("缺乏左括号\n");                    exit(0);                  }         default: p++; /* 其它字符不处理,指针向后移 */       }       if(StackEmpty(s)) /* 字符串结束时栈空 */         printf("括号匹配\n");       else         printf("缺乏右括号\n");   }}void main(){   check();}

3、行编辑
      简单的行编辑程序的功能是:接受用户从终端输入的程序或数据,为了能发现错误并及时改正,再设立一个数据缓冲区,用以接受用户输入的一行字符,然后逐行存入用户数据区。
     具体例题:当用户发现刚刚键入的一个字符是错误的时,可以补进一个退格符“#”,以表示前面的一个字符无效,若发现当前键入的行内差错较多或难以补救时,则可以键入一个退行符“@”,以表示当前行中的字符均无效。
           eg:whli##ilr#e(s#*s)
                      outcha@putchar(*s=#++)
               则实际有效的是下列两行
                  while(* s)
                      putchar(*s++);
     算法:
 void lineedit( )         {  initstack(s);            ch=getchar( );            while(ch!=eof)           { while(ch!=eof && ch!=‘\n’)                 {  switch(ch)                          {    case ‘#’ : pop(s,c);                               case ‘@’ : clearstack(s);                               default : push(s,ch);                           }                     ch=getchar( );                 }             clearstack(s);             if(ch!=eof)                  ch=getchar( );           }           destroystack(s);   }

   具体代码的实现(C):
#include<string.h>#include<ctype.h>#include<malloc.h> /* malloc()等 */#include<limits.h> /* INT_MAX等 */#include<stdio.h> /* EOF(=^Z或F6),NULL */#include<stdlib.h> /* atoi() */#include<io.h> /* eof() */#include<math.h> /* floor(),ceil(),abs() */#include<process.h> /* exit() */FILE *fp;#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */#define STACKINCREMENT 2 /* 存储空间分配增量 */typedef struct SqStack{   char *base; /* 在栈构造之前和销毁之后,base的值为NULL */   char *top; /* 栈顶指针 */   int stacksize; /* 当前已分配的存储空间,以元素为单位 */}SqStack; /* 顺序栈 */int InitStack(SqStack *S){ /* 构造一个空栈S */   (*S).base=(char *)malloc(STACK_INIT_SIZE*sizeof(char));   if(!(*S).base)     exit(-2); /* 存储分配失败 */   (*S).top=(*S).base;   (*S).stacksize=STACK_INIT_SIZE;   return 1;}int DestroyStack(SqStack *S){ /* 销毁栈S,S不再存在 */   free((*S).base);   (*S).base=NULL;   (*S).top=NULL;   (*S).stacksize=0;   return 1;}int ClearStack(SqStack *S){ /* 把S置为空栈 */   (*S).top=(*S).base;   return 1;}int StackEmpty(SqStack S){ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */   if(S.top==S.base)     return 1;   else     return 0;}int GetTop(SqStack S,char *e){ /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */   if(S.top>S.base)   {     *e=*(S.top-1);     return 1;   }   else     return 0;}int Push(SqStack *S,char e){ /* 插入元素e为新的栈顶元素 */   if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */   {     (*S).base=(char *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(char));     if(!(*S).base)       exit(-2); /* 存储分配失败 */     (*S).top=(*S).base+(*S).stacksize;     (*S).stacksize+=STACKINCREMENT;   }   *((*S).top)++=e;   return 1;}int Pop(SqStack *S,char *e){ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */   if((*S).top==(*S).base)     return 0;   *e=*--(*S).top;   return 1;}int StackTraverse(SqStack S,int(*visit)(char)){ /* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 */   /* 一旦visit()失败,则操作失败 */   while(S.top>S.base)     visit(*S.base++);   printf("\n");   return 1;}int copy(char c){ /* 将字符c送至fp所指的文件中 */   fputc(c,fp);   return 1;}void LineEdit(){ /* 利用字符栈s,从终端接收一行并送至调用过程的数据区。算法3.2 */   SqStack s;   char ch,c;   InitStack(&s);   printf("请输入一个文本文件,^Z结束输入:\n");   ch=getchar();   while(ch!=EOF)   { /* EOF为^Z键,全文结束符 */     while(ch!=EOF&&ch!='\n')     {       switch(ch)       {         case '#':Pop(&s,&c);                  break; /* 仅当栈非空时退栈 */         case '@':ClearStack(&s);                  break; /* 重置s为空栈 */         default :Push(&s,ch); /* 有效字符进栈 */       }       ch=getchar(); /* 从终端接收下一个字符 */     }     StackTraverse(s,copy); /* 将从栈底到栈顶的栈内字符传送至文件 */     ClearStack(&s); /* 重置s为空栈 */     fputc('\n',fp);     if(ch!=EOF)       ch=getchar();   }   DestroyStack(&s);}void main(){   fp=fopen("ED.DAT","w"); /* 在当前目录下建立ED.DAT文件,用于写数据, */   if(fp)                  /* 如已有同名文件则先删除原文件 */   {     LineEdit();     fclose(fp); /* 关闭fp所指的文件 */   }   else     printf("建立文件失败!\n");}

4、表达式求值
     表达式求值是程序设计语言中的一个最基本问题。在此应用栈的“后进先出”的特点,介绍一种“算法优先级”算法。
     算术四则运算的规则:
       (1) 先乘除,后加减。
       (2)从左算到右。
       (3)先括号内,后括号外。
为实现算符优先算法,可使用两个工作栈:

    OPND栈:存数据或运算结果 

    OPTR栈:存运算符
算法原理:
   1.初态: 置OPND栈为空;将#作为OPTR栈的栈底元素

    2.依次读入表达式中的每个字符

    1)若是操作数,则进入OPND栈;

    2)若是运算符,则与OPTR栈的栈顶运算符进行优先权(级)的比较:

§ 若读入运算符的优先权高,则进入OPTR栈;
§若读入运算符的优先权低,则OPTR退栈(退出

  原有的栈顶元素),OPND栈退出两个元素

 (先退出b,再退出a),中间结果再进入OPND栈;

§若读入OPTR栈的原有栈的栈顶元素若为

  ,则OPTR退出

§若读入#OPTR栈栈顶元素也为#,则OPTR栈退出#,结束
   
   算法:
 OperandType   EvaluateExpression( ){  / /OPTR为运算符栈,OPND为运算数,OP为运算符集   InitStack(OPTR);   Push(OPTR,'#');   InitStack(OPND);   c=getchar();   while(c!='#'||GetTop(OPTR)!='#'){         if(! In(c,OP))           { Push(OPND,c);c=getchar();}         else           switch (Precede(GetTop(OPTR),c)) {               case '<':                          Push(OPTR,c); c=getchar();break;               case '=':                          Pop(OPTR,x);c=getchar();break;               case '>':                          Pop(OPTR,theta);                          Pop(OPND,b);Pop(OPND,a);                          Push(OPND,OPerate(a,theta,b));break;             }     } return GetTop(OPND);}

   具体代码的实现(C):
 #include<string.h> #include<ctype.h> #include<malloc.h> /* malloc()等 */ #include<stdio.h> /* EOF(=^Z或F6),NULL */ #include<process.h> /* exit() */ #define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */ #define STACKINCREMENT 2 /* 存储空间分配增量 */ typedef struct SqStack {   char *base; /* 在栈构造之前和销毁之后,base的值为NULL */   char *top; /* 栈顶指针 */   int stacksize; /* 当前已分配的存储空间,以元素为单位 */ }SqStack; /* 顺序栈 */ int InitStack(SqStack *S) { /* 构造一个空栈S */   (*S).base=(char *)malloc(STACK_INIT_SIZE*sizeof(char));   if(!(*S).base)     exit(-2); /* 存储分配失败 */   (*S).top=(*S).base;   (*S).stacksize=STACK_INIT_SIZE;   return 1; } int GetTop(SqStack S,char *e) { /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */   if(S.top>S.base)   {     *e=*(S.top-1);     return 1;   }   else     return 0; } int Push(SqStack *S,char e) { /* 插入元素e为新的栈顶元素 */   if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */   {     (*S).base=(char *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(char));     if(!(*S).base)       exit(-2); /* 存储分配失败 */     (*S).top=(*S).base+(*S).stacksize;     (*S).stacksize+=STACKINCREMENT;   }   *((*S).top)++=e;   return 1; } int Pop(SqStack *S,char *e) { /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */   if((*S).top==(*S).base)     return 0;   *e=*--(*S).top;   return 1; } int StackTraverse(SqStack S,int(*visit)(char)) { /* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 */   /* 一旦visit()失败,则操作失败 */   while(S.top>S.base)     visit(*S.base++);   printf("\n");   return 1; } char Precede(char t1,char t2) { /* 判断两符号的优先关系 */   char f;   switch(t2)   {     case '+':     case '-':if(t1=='('||t1=='#')                f='<';              else                f='>';              break;     case '*':     case '/':if(t1=='*'||t1=='/'||t1==')')                f='>';              else                f='<';              break;     case '(':if(t1==')')              {                printf("ERROR1\n");                exit(0);              }              else                f='<';              break;     case ')':switch(t1)              {                case '(':f='=';                         break;                case '#':printf("ERROR2\n");                         exit(0);                default: f='>';              }              break;     case '#':switch(t1)              {                case '#':f='=';                         break;                case '(':printf("ERROR3\n");                         exit(0);                default: f='>';              }   }   return f; } int In(char c) { /* 判断c是否为运算符 */   switch(c)   {     case'+':     case'-':     case'*':     case'/':     case'(':     case')':     case'#':return 1;     default:return 0;   } } char Operate(char a,char theta,char b) {   char c;   a=a-48;   b=b-48;   switch(theta)   {     case'+':c=a+b+48;             break;     case'-':c=a-b+48;             break;     case'*':c=a*b+48;             break;     case'/':c=a/b+48;   }   return c; } char EvaluateExpression()  { /* 算术表达式求值的算符优先算法。设OPTR和OPND分别为运算符栈和运算数栈 */   SqStack OPTR,OPND;   char a,b,c,x,theta;   InitStack(&OPTR);   Push(&OPTR,'#');   InitStack(&OPND);   c=getchar();   GetTop(OPTR,&x);   while(c!='#'||x!='#')   {     if(In(c)) /* 是7种运算符之一 */       switch(Precede(x,c))       {         case'<':Push(&OPTR,c); /* 栈顶元素优先权低 */                 c=getchar();                 break;         case'=':Pop(&OPTR,&x); /* 脱括号并接收下一字符 */                 c=getchar();                 break;         case'>':Pop(&OPTR,&theta); /* 退栈并将运算结果入栈 */ Pop(&OPND,&b);                 Pop(&OPND,&a);                 Push(&OPND,Operate(a,theta,b));                 break;       }     else if(c>='0'&&c<='9') /* c是操作数 */     {       Push(&OPND,c);       c=getchar();     }     else /* c是非法字符 */     {       printf("ERROR4\n");       exit(-2);     }     GetTop(OPTR,&x);   }   GetTop(OPND,&x);   return x; } void main() {   printf("请输入算术表达式(中间值及最终结果要在0~9之间),并以#结束\n");   printf("%c\n",EvaluateExpression()); }





0 0
原创粉丝点击