当前位置:   article > 正文

关于栈及其应用示例_栈的应用实例

栈的应用实例

 

作为一种常用的数据结构, 了解栈对于算法的学习是非常必要的。栈有先进后出的特点,栈底指向数据表中的第一个元素,栈顶指向最后一个元素的下一个位置。如下图所示:

 

 

 

栈和线性表类似,也是有两种存储结构,分别为顺序结构和链式结构。大部分情况下,栈使用前者,这和它的使用场景有关,因为通常情况下我们不会对栈进行频繁地,随机地插入,删除操作。下面是我用顺序结构实现的栈,这个栈有个特点就是它的通用性,因为我并没有限制它所存储的数据类型,代码如下:

 

  1. //void**其为双指针,意味入栈和出栈的将只是对应数据的地址,而不需要对数据本身进行拷贝
  2. typedef struct
  3. {
  4. char *base;
  5. char *top;
  6. int elementSize; //元素所点字节大小
  7. int stackSize; //当前已分配的空间(注意不是元素的实际个数)
  8. }ponyStack;
  9. int InitStack(ponyStack *stack, int elementSize)
  10. {
  11. stack->base = (char *)malloc(STACK_INIT_SIZE * sizeof(char)*elementSize);
  12. if (!stack->base)
  13. {
  14. return RET_ERROR;
  15. }
  16. stack->top = stack->base; //为空
  17. stack->stackSize = STACK_INIT_SIZE;
  18. stack->elementSize = elementSize;
  19. return RET_OK;
  20. }
  21. int ClearStack(ponyStack *stack)
  22. {
  23. stack->top = stack->base;
  24. return RET_OK;
  25. }
  26. bool IsEmptyStack(ponyStack stack)
  27. {
  28. if (stack.top == stack.base)
  29. {
  30. return true;
  31. }
  32. return false;
  33. }

 

这里没有贴出全部的代码,更完整的可以从最后的地址那里下载。注意elementSize,这个是栈可以做到通用的核心。不理解的可以再研究一下代码。

 

 

看一个栈的使用示例,数制转换。十进制转八进制。例如(1348)十进制= (2504)八进制,它基于如下的原理:

   N             N/8             N%8

  1348        168               4

  168           21                0

   21             2                  5

   2               0                   2

 

所以很明显,N不断的除8,每次的余数就是结果的其中一个因子,注意先出来的因子是低位的数,可以考虑用栈来保存每次取余的结果,那么出栈的顺序就是实际的结果顺序。代码很简单:

 

  1. int decimalToOctonary(int decimalNumber)
  2. {
  3. double octNumber = 0;
  4. int nCount = 0;
  5. int nTemp = 0;
  6. ponyStack numberStack;
  7. InitStack(&numberStack, 4);
  8. while (decimalNumber)
  9. {
  10. nTemp = (int)decimalNumber%8;
  11. Push(&numberStack, &nTemp);
  12. decimalNumber = decimalNumber/8;
  13. }
  14. nCount = CountOfStack(numberStack);//元素个数也就是位数
  15. while(!IsEmptyStack(numberStack))
  16. {
  17. Pop(&numberStack, &nTemp);
  18. octNumber += (nTemp*pow(10.0, --nCount));
  19. }
  20. DestroyStack(&numberStack);
  21. return (int)octNumber;
  22. }

 

 

再来看一个行编辑程序的示例,用户在终端输入字符,完成后保存用户的数据区, 因为在输入的过程中可能出错,需要修改,所以不可能每输入一个字符就存入数据区。比较好的做法是先在内存里开一个输入的缓冲区,当用户输入完成一行后,再存入数据区。在行内可以修改。例如,当用户发现刚输入的一个字符是错的之后,可以再输入一个'#',表示前一个字符是错的,如果发现当前行输入的错误太多,可以输入一个退行符'@',表示当前行都无效,举个例子:

whli#ilr#e(s#*s)

outcha@putchar(*s=#++)

实际有效的字符是这样的:

while(*s)

putchar(*s++)

 

可以把内存里这个输入缓冲区定为栈,正常情况下每输入一个字符直接入栈,如果发现字符是'#',就栈顶pop一次,如果是'@'就清空栈.代码实现如下:

 

  1. void lineEdit()
  2. {
  3. char ch = 0;
  4. char chTemp = 0;
  5. ponyStack lineStack;
  6. InitStack(&lineStack, 1);
  7. ch = getchar();
  8. while (ch != EOF)
  9. {
  10. while (ch != EOF && ch != '\n')
  11. {
  12. switch (ch)
  13. {
  14. case '#':
  15. Pop(&lineStack, &chTemp);
  16. break;
  17. case '@':
  18. ClearStack(&lineStack);
  19. break;
  20. default:
  21. Push(&lineStack, &ch);
  22. break;
  23. }
  24. ch = getchar();
  25. }
  26. writeToFile(lineStack);//存数据
  27. ClearStack(&lineStack);//准备接收下一行
  28. if (ch != EOF)
  29. {
  30. ch = getchar();
  31. }
  32. }
  33. DestroyStack(&lineStack);
  34. }

 

 

 

 

 

最后一个例子是表达式求值的算法,这个在计算器应用中比较多用到。比如,

求+4*9-16/4

建两个栈,一个存操作数,一个存运算符.为简单起,在运算符栈会预先存一个'#',表示表达式开始,然后以'#'结束。运算规则是这样的:

输入字符,如果是'#',则结束,如果是操作数,直接进操作数栈。如果是运算符,则跟栈顶的运算符比较,如果栈顶的优先级低,直接进栈,接收下一字符,如果相等,脱括号,接收下一个字符,如果栈顶的优先级高,pop两个操作数,pop栈内操作符,运算,然后运算的结果进操作数栈。当前运算符继续跟栈顶比较。

 

要实现这个代码,首先要有一个表格,存储我们操作符之间的优先级关系,如下所示:

 

  1. static char priority[7][7] = {
  2. '>','>','<','<','<','>','>', // +
  3. '>','>','<','<','<','>','>', // -
  4. '>','>','>','>','<','>','>', // *
  5. '>','>','>','>','<','>','>', // /
  6. '<','<','<','<','<','=',' ', // (
  7. '>','>','>','>',' ','>','>', // )
  8. '<','<','<','<','<',' ','=', // #
  9. };// + - * / ( ) #

 

 

 

 

 

然后实现根据上面的思路,实现起来就比较容易了:

 

  1. int evaluateExpression()
  2. {
  3. char chCurrent = 0;
  4. char chOnTop = 0;
  5. char chTemp = 0;
  6. int nResult = 0;
  7. int nTemp = 0;
  8. int a,b;
  9. int nOperandFlag = 0;
  10. ponyStack operatorStack;//运算符栈
  11. ponyStack operandStack; //操作数栈
  12. InitStack(&operatorStack, 1);
  13. chTemp = '#';
  14. Push(&operatorStack, &chTemp);
  15. InitStack(&operandStack, 4);
  16. chCurrent = getchar();
  17. GetTop(operatorStack, &chOnTop);
  18. while ((chCurrent != '#')||(chOnTop != '#'))
  19. {
  20. if (!isOperator(chCurrent))//是操作数,要考虑多位整型数的情况
  21. {
  22. nTemp = nTemp * (int)pow(10.0, nOperandFlag);
  23. nTemp += (int)(chCurrent - '0');
  24. chCurrent = getchar();
  25. nOperandFlag = 1;
  26. }
  27. else
  28. {
  29. if (nOperandFlag == 1)
  30. {
  31. Push(&operandStack, &nTemp);//操作数输入结束,入栈
  32. nOperandFlag = 0;
  33. nTemp = 0;
  34. }
  35. GetTop(operatorStack, &chOnTop);
  36. switch (precede(chOnTop, chCurrent))//比较优先级
  37. {
  38. case '<': //栈顶的优先级小
  39. Push(&operatorStack, &chCurrent);
  40. chCurrent = getchar();
  41. GetTop(operatorStack, &chOnTop);
  42. break;
  43. case '=': //脱括号,接收下个字符
  44. Pop(&operatorStack, &chTemp);
  45. chCurrent = getchar();
  46. GetTop(operatorStack, &chOnTop);
  47. break;
  48. case '>': //栈顶的优先级大,出栈运算,结果入栈
  49. {
  50. Pop(&operandStack, &a);
  51. Pop(&operandStack, &b);
  52. Pop(&operatorStack, &chTemp);
  53. nTemp = operate(a, chTemp, b);
  54. Push(&operandStack, &nTemp);
  55. nTemp = 0;//重置
  56. GetTop(operatorStack, &chOnTop);
  57. }
  58. break;
  59. default:
  60. break;
  61. }
  62. }
  63. }
  64. GetTop(operandStack, &nResult);
  65. DestroyStack(&operatorStack);
  66. DestroyStack(&operandStack);
  67. return nResult;
  68. }

 

 

 

 

 

代码下载地址:

https://github.com/pony-maggie/StackDemo

http://download.csdn.net/detail/pony_maggie/7499167

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/1022513
推荐阅读
相关标签
  

闽ICP备14008679号