栈和队列的介绍

栈和队列是两种重要的线性结构,从数据结构角度看,栈和队列也是线性表,其特殊性在与栈和队列的基本操作是线性表操作的子集,它们是受限制的线性表,因此可称为限定性数据结构,但从数据类型角度看,它们是和线性表大不相同的两类重要的抽象数据类型。
队列和栈都可以使用顺序线性表和链线性表的方式实现

是限定仅在表尾进行插入或删除操作的线性表。因此,对栈来说,表尾端有其特殊的含义,称为“栈顶”,相应的表头端称为“栈底”。不含元素的空表叫做“空栈”,栈又叫做先进后出的线性表。

  • InitStack(&S); // 初始化栈
  • DestroyStack(&S); // 销毁栈
  • ClearStack(&S); // 清空栈
  • StackEmpty(&S); // 检测是不是空栈,若为空返回TRUE,不为空返回FALSE
  • StackLength(&S); // 返回栈的长度
  • StackGetTop(&S, &e); // 返回栈顶元素
  • StackPush(&S, &e); // 向栈顶插入元素
  • StackPop(&S, &e); // 删除栈顶元素,并通过e返回
  • StackTraverse(&S, visit()); // 栈中所有元素依次调用visit()。一旦visit()失败,则操作失败

和线性表一样,栈也有两种存储表示方式(顺序栈,先给个默认长度,然后在给一个递增长度,递增类型的)

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define TRUE 1
  4. #define FALSE 0
  5. #define ERROR 0
  6. #define OK 1
  7. #define OVERFLOW -2
  8. #define STACK_INIT_SIZE 100
  9. #define STACKINCREMENT 10
  10. typedef int ElemType;
  11. typedef int Status;
  12. typedef struct {
  13. ElemType *base; // 栈底
  14. ElemType *top; // 栈顶
  15. int stacksize;
  16. }SqStack;
  17. Status InitStack(SqStack *S) {
  18. S -> base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
  19. if (!S-> base) {
  20. exit(OVERFLOW);
  21. }
  22. S -> top = S -> base;
  23. S -> stacksize = STACK_INIT_SIZE;
  24. return OK;
  25. }
  26. Status StackGetTop(SqStack *S, ElemType *e) {
  27. if (S -> top == S -> base) {
  28. return ERROR;
  29. }
  30. *e = *(S -> top -1);
  31. return OK;
  32. }
  33. Status StackPush(SqStack *S, ElemType e) {
  34. if (S -> top - S -> base >= S -> stacksize) {
  35. S -> base = (ElemType *)realloc(S -> base,
  36. (S -> stacksize + STACKINCREMENT) * sizeof(ElemType));
  37. if (!S -> base) {
  38. exit(OVERFLOW);
  39. }
  40. S -> top = S -> base + S -> stacksize;
  41. S -> stacksize += STACKINCREMENT;
  42. }
  43. *S -> top++ = e;
  44. return OK;
  45. }
  46. Status StackPop(SqStack *S, ElemType *e) {
  47. if (S -> top == S -> base ) {
  48. return ERROR;
  49. }
  50. *e = *--S -> top;
  51. return OK;
  52. }
  53. Status StackEmpty(SqStack *S) {
  54. Status z = S -> top == S -> base ? TRUE : FALSE;
  55. return z;
  56. }
  57. int main() {
  58. SqStack S;
  59. InitStack(&S);
  60. // ElemType e = 2;
  61. // ElemType v;
  62. // StackPush(&S, e);
  63. // StackPop(&S, &v);
  64. // StackGetTop(&S, &v);
  65. // printf("d=%d\n", v);
  66. int n;
  67. ElemType e;
  68. scanf("%d", &n);
  69. while (n) {
  70. StackPush(&S, n % 8);
  71. n /= 8;
  72. }
  73. while(!StackEmpty(&S)) {
  74. StackPop(&S, &e);
  75. printf("%d", e);
  76. }
  77. printf("\n");
  78. return 0;
  79. }

栈的应用实例

数制转换

(1348)十进制 = (2504) 八进制
1348 % 8 = 4
1348 / 8 = 168; 168 % 8 = 0;
168 / 8 = 21; 21 % 8 = 5;
21 / 8 = 2; 2 % 8 = 2;

  1. int main() {
  2. SqStack S;
  3. InitStack(&S);
  4. int n;
  5. ElemType e;
  6. scanf("%d", &n);
  7. while (n) {
  8. StackPush(&S, n % 8);
  9. n /= 8;
  10. }
  11. while(!StackEmpty(&S)) {
  12. StackPop(&S, &e);
  13. printf("%d", e);
  14. }
  15. printf("\n");
  16. return 0;
  17. }

行编辑程序

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define TRUE 1
  4. #define FALSE 0
  5. #define ERROR 0
  6. #define OK 1
  7. #define OVERFLOW -2
  8. #define STACK_INIT_SIZE 100
  9. #define STACKINCREMENT 10
  10. typedef char ElemType;
  11. typedef char Status;
  12. typedef struct {
  13. ElemType *base; // 栈底
  14. ElemType *top; // 栈顶
  15. int stacksize;
  16. }SqStack;
  17. Status InitStack(SqStack *S) {
  18. S -> base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
  19. if (!S-> base) {
  20. exit(OVERFLOW);
  21. }
  22. S -> top = S -> base;
  23. S -> stacksize = STACK_INIT_SIZE;
  24. return OK;
  25. }
  26. Status StackGetTop(SqStack *S, ElemType *e) {
  27. if (S -> top == S -> base) {
  28. return ERROR;
  29. }
  30. *e = *(S -> top -1);
  31. return OK;
  32. }
  33. Status StackPush(SqStack *S, ElemType e) {
  34. if (S -> top - S -> base >= S -> stacksize) {
  35. S -> base = (ElemType *)realloc(S -> base,
  36. (S -> stacksize + STACKINCREMENT) * sizeof(ElemType));
  37. if (!S -> base) {
  38. exit(OVERFLOW);
  39. }
  40. S -> top = S -> base + S -> stacksize;
  41. S -> stacksize += STACKINCREMENT;
  42. }
  43. *S -> top++ = e;
  44. return OK;
  45. }
  46. Status StackPop(SqStack *S, ElemType *e) {
  47. if (S -> top == S -> base ) {
  48. return ERROR;
  49. }
  50. *e = *--S -> top;
  51. return OK;
  52. }
  53. Status ClearStack(SqStack *S) {
  54. S -> top = S -> base;
  55. return OK;
  56. }
  57. Status StackEmpty(SqStack *S) {
  58. Status z = S -> top == S -> base ? TRUE : FALSE;
  59. return z;
  60. }
  61. void LineEdit(SqStack *S) {
  62. printf("请输入字符:\n");
  63. InitStack(S);
  64. char ch;
  65. scanf("%c", &ch);
  66. while ((int)ch != 27) {
  67. switch(ch) {
  68. case '#':
  69. StackPop(S, &ch);
  70. break;
  71. case '@': // 期待删除 \n?.*@.*\n 之间的内容
  72. ClearStack(S);
  73. break;
  74. default: StackPush(S, ch);
  75. }
  76. scanf("%c", &ch);
  77. if (ch == '\n') {
  78. StackPush(S, ch);
  79. scanf("%c", &ch);
  80. }
  81. }
  82. }
  83. int main() {
  84. SqStack S;
  85. LineEdit(&S);
  86. char e;
  87. while(!StackEmpty(&S)) {
  88. StackPop(&S, &e);
  89. printf("%c", e);
  90. }
  91. printf("\n");
  92. return 0;
  93. }

括号匹配的检测

{[][]{}}

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define TRUE 1
  4. #define FALSE 0
  5. #define ERROR 0
  6. #define NO 0
  7. #define OK 1
  8. #define OVERFLOW -2
  9. #define STACK_INIT_SIZE 100
  10. #define STACKINCREMENT 10
  11. typedef char ElemType;
  12. typedef char Status;
  13. typedef struct {
  14. ElemType *base; // 栈底
  15. ElemType *top; // 栈顶
  16. int stacksize;
  17. }SqStack;
  18. Status InitStack(SqStack *S) {
  19. S -> base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
  20. if (!S-> base) {
  21. exit(OVERFLOW);
  22. }
  23. S -> top = S -> base;
  24. S -> stacksize = STACK_INIT_SIZE;
  25. return OK;
  26. }
  27. Status StackGetTop(SqStack *S, ElemType *e) {
  28. if (S -> top == S -> base) {
  29. return ERROR;
  30. }
  31. *e = *(S -> top -1);
  32. return OK;
  33. }
  34. Status StackPush(SqStack *S, ElemType e) {
  35. if (S -> top - S -> base >= S -> stacksize) {
  36. S -> base = (ElemType *)realloc(S -> base,
  37. (S -> stacksize + STACKINCREMENT) * sizeof(ElemType));
  38. if (!S -> base) {
  39. exit(OVERFLOW);
  40. }
  41. S -> top = S -> base + S -> stacksize;
  42. S -> stacksize += STACKINCREMENT;
  43. }
  44. *S -> top++ = e;
  45. return OK;
  46. }
  47. Status StackPop(SqStack *S, ElemType *e) {
  48. if (S -> top == S -> base) {
  49. return ERROR;
  50. }
  51. *e = *--S -> top;
  52. return OK;
  53. }
  54. Status ClearStack(SqStack *S) {
  55. S -> top = S -> base;
  56. return OK;
  57. }
  58. Status StackEmpty(SqStack *S) {
  59. Status z = S -> top == S -> base ? TRUE : FALSE;
  60. return z;
  61. }
  62. Status Match(char a,char b){
  63. if (a + 1 == b || a + 2 == b) {
  64. return OK;
  65. }
  66. return NO;
  67. }
  68. Status BracketsMatching(char *str) {
  69. SqStack S;
  70. InitStack(&S);
  71. int i;
  72. char ch;
  73. for (i = 0; str[i] != '\0'; i++) {
  74. switch (str[i]) {
  75. case '{':
  76. case '(':
  77. case '[':
  78. StackPush(&S, str[i]);
  79. break;
  80. case '}':
  81. case ')':
  82. case ']':
  83. if (StackEmpty(&S)){
  84. return NO;
  85. }
  86. StackGetTop(&S, &ch);
  87. if (Match(ch, str[i])) {
  88. StackPop(&S, &ch);
  89. } else {
  90. return NO;
  91. }
  92. break;
  93. default:
  94. break;
  95. }
  96. }
  97. if (!StackEmpty(&S)) {
  98. return NO;
  99. }
  100. return OK;
  101. }
  102. int main() {
  103. Status StackEmpty(SqStack *S);
  104. Status StackPush(SqStack *S, ElemType e);
  105. Status StackPop(SqStack *S, ElemType *e);
  106. char str[50];
  107. printf("请输入你要收入的字符串:");
  108. scanf("%s", str);
  109. int h = BracketsMatching(str);
  110. if(h == 0)
  111. printf("括号不匹配\n");
  112. else
  113. printf("括号匹配\n");
  114. return 0;
  115. }

迷宫求解

求迷宫从入口到出口的所有路径是一个经典的程序设计问题。由于计算机解迷宫时,通常用的是“穷举求解”的方法,即从入口出发,顺某一个方向向前探索,若能走通,则继续向前,否则按原路退回,换一个方向继续探索,直至所有可能的路线都探索到了为止。为了保证在任何位置上都能按原路退回,显然需要用一个后进先出的结构来保存从入口到当前位置的路径。因此求解迷宫通路的算法中应用“栈”也就是自然而然的事情了。
首先,在计算机中可以用如图所示的方块图表示迷宫。图中空白处可以通行,阴影处表示是墙壁。所求路径必须是简单路径,即在求得路径上不能重复出现同一通道块。
假设“当前位置”指的是“在搜索过程中某一时刻所在图中某个方块的位置”,则求迷宫中一条路径的算法的基本思想是:
若当前位置“可通”,则纳入“当前路径”,并继续朝下一个位置探索,即切换“下一位置”为当前位置,如此反复直至到达出口;若当前位置“不可通”,则顺应“来向”退回到前一块通道,然后朝则除“来向”之外的其他地方探索;若该通道块的四周四个方块均不可通,则应顺从“当前路径”上删除该通道块。所谓“下一位置”指的是当前位置的四周4个方向(上,下,左,右)上相邻的方块。
假设栈S纪录当前路径,则栈顶中存放的是“当前路径上最后一个通道块”。由此“纳入路径”的操作即为“当前位置入栈“,“从当前路径上最后一个通道块”的操作即为“出栈”。

IMG_20190708_111943.jpg

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define TRUE 1
  4. #define FALSE 0
  5. #define ERROR 0
  6. #define NO 0
  7. #define OK 1
  8. #define OVERFLOW -2
  9. #define STACK_INIT_SIZE 100
  10. #define STACKINCREMENT 10
  11. typedef struct{
  12. int x;
  13. int y;
  14. }PosType;
  15. typedef struct{
  16. int ord; // 通道块在路径上的“序号”
  17. PosType seat; // 通道块在迷宫中的坐标位置
  18. int di; // 通道块走向下一通道块的方向 1上, 2右,3下,4左
  19. }MazeElemType;
  20. typedef struct {
  21. int rowsLength; // 行长度
  22. int columnLength; // 列长度
  23. int *mazeArr; // 地图数组
  24. }MazeType;
  25. typedef MazeElemType ElemType;
  26. typedef int Status;
  27. #define StatusPrintf "%d\n"
  28. typedef struct {
  29. ElemType *base; // 栈底
  30. ElemType *top; // 栈顶
  31. int stacksize;
  32. }SqStack;
  33. Status InitStack(SqStack *S) {
  34. S -> base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
  35. if (!S-> base) {
  36. exit(OVERFLOW);
  37. }
  38. S -> top = S -> base;
  39. S -> stacksize = STACK_INIT_SIZE;
  40. return OK;
  41. }
  42. Status StackGetTop(SqStack *S, ElemType *e) {
  43. if (S -> top == S -> base) {
  44. return ERROR;
  45. }
  46. *e = *(S -> top -1);
  47. return OK;
  48. }
  49. Status StackPush(SqStack *S, ElemType e) {
  50. if (S -> top - S -> base >= S -> stacksize) {
  51. S -> base = (ElemType *)realloc(S -> base,
  52. (S -> stacksize + STACKINCREMENT) * sizeof(ElemType));
  53. if (!S -> base) {
  54. exit(OVERFLOW);
  55. }
  56. S -> top = S -> base + S -> stacksize;
  57. S -> stacksize += STACKINCREMENT;
  58. }
  59. *S -> top++ = e;
  60. return OK;
  61. }
  62. Status StackPop(SqStack *S, ElemType *e) {
  63. if (S -> top == S -> base) {
  64. return ERROR;
  65. }
  66. *e = *--S -> top;
  67. return OK;
  68. }
  69. Status ClearStack(SqStack *S) {
  70. S -> top = S -> base;
  71. return OK;
  72. }
  73. Status StackEmpty(SqStack *S) {
  74. Status z = S -> top == S -> base ? TRUE : FALSE;
  75. return z;
  76. }
  77. PosType NextPos(PosType curpos, int di) {
  78. switch(di) {
  79. case 1:
  80. curpos.x -= 1;
  81. break;
  82. case 2:
  83. curpos.y += 1;
  84. break;
  85. case 3:
  86. curpos.x += 1;
  87. break;
  88. case 4:
  89. curpos.y -= 1;
  90. break;
  91. default:
  92. break;
  93. }
  94. int i = 0;
  95. int num = 0;
  96. for (; i < 1000000; i += 1) {
  97. num = i;
  98. }
  99. return curpos;
  100. }
  101. Status Pass(MazeType *maze, PosType curpos) { // 是否可通行块
  102. if (curpos.x > maze -> rowsLength
  103. || curpos.y > maze -> columnLength
  104. || curpos.x < 0
  105. || curpos.y < 0) {
  106. return FALSE;
  107. }
  108. int *p = maze -> mazeArr;
  109. int q = *(p + curpos.x * 10 + curpos.y);
  110. Status z = q > 0 ? TRUE : FALSE;
  111. return z;
  112. }
  113. Status MarkPrint(MazeType *maze, PosType curpos) { // 标记地图不能行走
  114. int *p = maze -> mazeArr;
  115. *(p + curpos.x * 10 + curpos.y) = 0;
  116. return OK;
  117. }
  118. Status TheWayThrough(SqStack *S, PosType temp) { // 判断是否存在链表中
  119. SqStack Temp;
  120. InitStack(&Temp);
  121. Status z = FALSE;
  122. MazeElemType e;
  123. while(!StackEmpty(S)) {
  124. StackPop(S, &e);
  125. StackPush(&Temp, e);
  126. if (e.seat.x == temp.x && e.seat.y == temp.y) {
  127. z = TRUE;
  128. }
  129. }
  130. while(!StackEmpty(&Temp)) {
  131. StackPop(&Temp, &e);
  132. StackPush(S, e);
  133. }
  134. return z;
  135. }
  136. /*
  137. 如果下个位置存在与链表中,跳过此次
  138. */
  139. Status CurposNext(MazeType *maze, SqStack *S, PosType *curpos, MazeElemType *e) {
  140. while (TheWayThrough(S, *curpos)) {
  141. if (e -> di == 4) {
  142. MarkPrint(maze, *curpos);
  143. StackPop(S, e);
  144. printf("F pop:%d:%d di=%d\n", e -> seat.x, e -> seat.y, e -> di);
  145. } else {
  146. StackPop(S, e);
  147. e -> di += 1;
  148. StackPush(S, *e);
  149. printf("E :%d:%d di=%d\n", e -> seat.x, e -> seat.y, e -> di);
  150. *curpos = NextPos(e -> seat, e -> di);
  151. }
  152. }
  153. return OK;
  154. }
  155. Status MazePath(MazeType *maze, PosType start, PosType end) {
  156. SqStack S;
  157. InitStack(&S);
  158. PosType curpos = start; // 设置起始位置 8,8
  159. int curstep = 1; // 第一步
  160. MazeElemType e;
  161. int i;
  162. do {
  163. i++;
  164. Status z = Pass(maze, curpos); // 是否可通行块
  165. if (z) { // 当前位置是可通行块
  166. e.ord = curstep;
  167. e.seat = curpos;
  168. e.di = 1; // 通过di留下足迹
  169. StackPush(&S, e);
  170. printf("A push:%d:%d di=%d\n", e.seat.x, e.seat.y, e.di);
  171. if (curpos.x == end.x
  172. && curpos.y == end.y) {
  173. printf("i=%d\n", i);
  174. return OK;
  175. }
  176. curpos = NextPos(curpos, 1); // 下一个位置
  177. CurposNext(maze, &S, &curpos, &e);
  178. curstep++;
  179. } else { // 当前位置为不可通行块
  180. if (!StackEmpty(&S)) {
  181. StackPop(&S, &e);
  182. printf("B pop:%d:%d di=%d\n", e.seat.x, e.seat.y, e.di);
  183. while(e.di == 4 && !StackEmpty(&S)) {
  184. // 标记地图不可通行
  185. MarkPrint(maze, curpos);
  186. StackPop(&S, &e);
  187. printf("D MarkPrint pop:%d:%d di=%d\n", e.seat.x, e.seat.y, e.di);
  188. curpos = e.seat;
  189. }
  190. if (e.di < 4) {
  191. e.di += 1;
  192. StackPush(&S, e);
  193. printf("C push:%d:%d di=%d\n", e.seat.x, e.seat.y, e.di);
  194. curpos = NextPos(e.seat, e.di);
  195. CurposNext(maze, &S, &curpos, &e);
  196. }
  197. }
  198. }
  199. } while (!StackEmpty(&S));
  200. printf("i=%d\n", i);
  201. return FALSE;
  202. }
  203. int main() {
  204. Status StackEmpty(SqStack *S);
  205. Status StackPush(SqStack *S, ElemType e);
  206. Status StackPop(SqStack *S, ElemType *e);
  207. Status MarkPrint(MazeType *maze, PosType curpos);
  208. PosType NextPos(PosType curpos, int di);
  209. Status Pass(MazeType *maze, PosType curpos);
  210. Status MazePath(MazeType *maze, PosType start, PosType end);
  211. Status TheWayThrough(SqStack *S, PosType temp);
  212. Status CurposNext(MazeType *maze, SqStack *S, PosType *curpos, MazeElemType *e);
  213. int Maze[10][10] = { // 迷宫 2为出口,3为入口,1为可通行块,0为不可通行块
  214. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  215. { 0, 2, 1, 0, 1, 1, 1, 0, 1, 0 },
  216. { 0, 1, 1, 0, 1, 1, 1, 0, 1, 0 },
  217. { 0, 1, 1, 1, 1, 0, 0, 1, 1, 0 },
  218. { 0, 1, 0, 0, 0, 1, 1, 1, 1, 0 },
  219. { 0, 1, 1, 1, 0, 1, 1, 1, 1, 0 },
  220. { 0, 1, 0, 1, 1, 1, 0, 1, 1, 0 },
  221. { 0, 1, 0, 0, 0, 1, 0, 0, 1, 0 },
  222. { 0, 0, 1, 1, 1, 1, 1, 1, 3, 0 },
  223. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  224. };
  225. int *p = &Maze[0][0];
  226. MazeType maze = { 10, 10, p };
  227. PosType start = { 8, 8 };
  228. PosType end = { 1, 1 };
  229. int i = MazePath(&maze, start, end);
  230. if (i == 0) {
  231. printf("没有找到出口\n");
  232. } else {
  233. printf("找到出口了\n");
  234. }
  235. return 0;
  236. }

表达式求值

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define TRUE 1
  4. #define FALSE 0
  5. #define OK 1
  6. #define ERROR 0
  7. #define INFEASIBLE -1
  8. #define OVERFLOW -2
  9. #define STACK_INIT_SIZE 100 //存储空间初始分配量
  10. #define STACKINCREMENT 10 //存储空间分配增量
  11. typedef char SElemType;
  12. typedef char OperandType; //表达式求值的运算类型
  13. typedef int Status;
  14. typedef struct
  15. {
  16. SElemType *base;
  17. SElemType *top;
  18. int stacksize;
  19. }SqStack;
  20. //构造一个空栈
  21. Status InitStack(SqStack *S)
  22. {
  23. S->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
  24. if(!S->base)
  25. {
  26. printf("内存分配失败!\n");
  27. exit(OVERFLOW);
  28. }
  29. S->top = S->base;
  30. S->stacksize = STACKINCREMENT;
  31. return OK;
  32. }
  33. //若栈不为空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
  34. Status GetTop(SqStack *S, SElemType *e)
  35. {
  36. if(S->top == S->base)
  37. return ERROR;
  38. *e = *(S->top - 1);
  39. return OK;
  40. }
  41. //插入元素e为新的栈顶元素
  42. Status Push(SqStack *S, SElemType e)
  43. {
  44. if(S->top - S->base >= STACK_INIT_SIZE) //栈满, 追加存储空间
  45. {
  46. S->base = (SElemType *)realloc(S->base, (S->stacksize + STACKINCREMENT) * sizeof(SElemType));
  47. if(!S->base)
  48. {
  49. printf("内存分配失败!\n");
  50. exit(OVERFLOW);
  51. }
  52. S->top = S->base + S->stacksize;
  53. S->stacksize += STACKINCREMENT;
  54. }
  55. *S->top++ = e;
  56. return OK;
  57. }
  58. //若栈不为空,则删除S的栈顶元素,用e返回其值,并返回Ok;否则返回ERROR
  59. Status Pop(SqStack *S, SElemType *e)
  60. {
  61. if(S->top == S->base)
  62. return ERROR;
  63. *e = *--S->top;
  64. return OK;
  65. }
  66. //销毁栈S,使其不复存在
  67. Status StackDestroy(SqStack *S)
  68. {
  69. free(S->base);
  70. S->base = NULL;
  71. S->top = NULL;
  72. S->stacksize = 0;
  73. return OK;
  74. }
  75. //清空栈S,保留栈底指针
  76. void ClearStack(SqStack *S)
  77. {
  78. S->top = S->base;
  79. }
  80. //根据教科书表3.1,判断两符号的优先关系
  81. char Precede(char t1, char t2){
  82. int i,j;
  83. char pre[][7]={
  84. //运算符之间的优先级制作成一张表格
  85. {'>','>','<','<','<','>','>'},
  86. {'>','>','<','<','<','>','>'},
  87. {'>','>','>','>','<','>','>'},
  88. {'>','>','>','>','<','>','>'},
  89. {'<','<','<','<','<','=','0'},
  90. {'>','>','>','>','0','>','>'},
  91. {'<','<','<','<','<','0','='}};
  92. switch(t1){
  93. case '+': i=0; break;
  94. case '-': i=1; break;
  95. case '*': i=2; break;
  96. case '/': i=3; break;
  97. case '(': i=4; break;
  98. case ')': i=5; break;
  99. case '=': i=6; break;
  100. }
  101. switch(t2){
  102. case '+': j=0; break;
  103. case '-': j=1; break;
  104. case '*': j=2; break;
  105. case '/': j=3; break;
  106. case '(': j=4; break;
  107. case ')': j=5; break;
  108. case '=': j=6; break;
  109. }
  110. return pre[i][j];
  111. }
  112. //判断c是否为运算符
  113. Status In(OperandType c)
  114. {
  115. switch(c)
  116. {
  117. case '+':
  118. case '-':
  119. case '*':
  120. case '/':
  121. case '(':
  122. case ')':
  123. case '=':
  124. return TRUE;
  125. default:
  126. return FALSE;
  127. }
  128. }
  129. //二元运算(a theta b)
  130. OperandType Operate(OperandType a, OperandType theta, OperandType b)
  131. {
  132. OperandType c;
  133. switch(theta)
  134. {
  135. case '+':
  136. c = a + b;
  137. break;
  138. case '-':
  139. c = a - b;
  140. break;
  141. case '*':
  142. c = a * b;
  143. break;
  144. case '/':
  145. c = a / b;
  146. break;
  147. }
  148. return c;
  149. }
  150. //算术表达式求值的算符优先算法,设OPTR和OPND分别为运算符栈和运算数栈,OP为运算符集合
  151. OperandType EvaluateExpression()
  152. {
  153. SqStack OPTR, OPND;
  154. OperandType a, b, d, x, theta;
  155. char c; //存放有键盘输入的字符串
  156. char z[6]; //存放整数字符串
  157. int i;
  158. InitStack(&OPTR); //初始化运算符栈
  159. Push(&OPTR, '='); //=是表达式结束符
  160. InitStack(&OPND); //初始化运算数栈
  161. c = getchar();
  162. GetTop(&OPTR, &x);
  163. while(c != '=' || x != '=')
  164. {
  165. if(In(c)) //是7种运算符之一
  166. {
  167. printf("%c\n", Precede(x, c));
  168. switch(Precede(x, c))
  169. {
  170. case '<': //当前已经压栈一个运算符(x)比后一个运算符(c)低时,就将c压栈
  171. Push(&OPTR, c);
  172. c = getchar();
  173. break;
  174. case '=':
  175. Pop(&OPTR, &x); //脱括号并接收下一字符
  176. c = getchar();
  177. break;
  178. case '>':
  179. Pop(&OPTR, &theta); //退栈并将运算结果压入OPND中
  180. Pop(&OPND, &b);
  181. Pop(&OPND, &a);
  182. Push(&OPND, Operate(a, theta, b));
  183. break;
  184. }
  185. }
  186. else if(c >= '0' && c <= '9') //c是操作数
  187. {
  188. i = 0;
  189. do
  190. {
  191. z[i] = c;
  192. i++;
  193. c = getchar();
  194. }while(c >= '0' && c <= '9');
  195. z[i] = 0;
  196. d = atoi(z); //将字符数组转为整型存于d
  197. printf("%d\n", d);
  198. Push(&OPND, d);
  199. }
  200. else //c为非法字符
  201. {
  202. printf("ERROR3\n");
  203. exit(1);
  204. }
  205. GetTop(&OPTR, &x);
  206. }
  207. GetTop(&OPND, &x);
  208. StackDestroy(&OPTR);
  209. StackDestroy(&OPND);
  210. return x;
  211. }
  212. int main()
  213. {
  214. printf("请输入算术表达式,负数要用(0-正数:\n");
  215. printf("%d\n", EvaluateExpression());
  216. return 0;
  217. }

栈和递归 hanoi塔

  1. #include <stdio.h>
  2. int c = 0;
  3. void move(char a,int m,char b);
  4. void hanoi(int n,char x,char y,char z);
  5. int main()
  6. {
  7. int n = 4;
  8. char x = 'x';
  9. char y = 'y';
  10. char z = 'z';
  11. hanoi(n,x,y,z);
  12. }
  13. void hanoi(int n,char x,char y,char z)
  14. //将塔座x上按直径由小到大且自上而下编号为1至n的n个圆盘按规则搬到
  15. //塔座z上,y可用辅助塔座。
  16. {
  17. if(n==1)
  18. move(x,1,z);
  19. else
  20. {
  21. hanoi(n-1,x,z,y);
  22. move(x,n,z);
  23. hanoi(n-1,y,x,z);
  24. }
  25. }
  26. void move(char a,int m,char b)
  27. {
  28. printf("第%d步:将第%d个圆盘从%c移到%c\n",++c,m,a,b);
  29. }

队列

  • 和栈相反队列是一种先进先出的线性表,也是利用线性表的实现
  • 有一种队列叫做,双端队列,两头都可以删除和插入,分为端点1,端点2

IMG_20190710_171103.jpg

链队列

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define TRUE 1
  4. #define FALSE 0
  5. #define ERROR 0
  6. #define NO 0
  7. #define OK 1
  8. #define OVERFLOW -2
  9. #define STACK_INIT_SIZE 100
  10. #define STACKINCREMENT 10
  11. typedef int QElemType;
  12. typedef int Status;
  13. typedef struct QNode{
  14. QElemType data;
  15. struct QNode *next;
  16. }QNode, *QueuePtr;
  17. typedef struct {
  18. QueuePtr front; // 对头指针
  19. QueuePtr rear; // 队尾指针
  20. }LinkQueue;
  21. Status InitQueue(LinkQueue *Q) {
  22. Q -> front = Q -> rear = (QueuePtr)malloc(sizeof(QNode));
  23. if (!Q-> front) {
  24. exit(OVERFLOW);
  25. }
  26. Q -> front = NULL;
  27. return OK;
  28. }
  29. Status EnQueue(LinkQueue *Q, QElemType e) {
  30. QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
  31. if (!p) {
  32. exit(OVERFLOW);
  33. }
  34. p -> data = e;
  35. p -> next = NULL;
  36. Q -> rear -> next = p;
  37. Q -> rear = p;
  38. return OK;
  39. }
  40. Status DeQueue(LinkQueue *Q, QElemType *e) {
  41. if (Q -> front == Q -> rear) {
  42. return ERROR;
  43. }
  44. QueuePtr p = Q -> front -> next;
  45. *e = p -> data;
  46. Q -> front -> next = p -> next;
  47. if (Q -> rear == p) {
  48. Q -> rear = Q -> front;
  49. }
  50. free(p);
  51. return OK;
  52. }
  53. int main () {
  54. return 0;
  55. }

IMG_20190710_164105.jpg

循环队列—队列的顺序表示

  • 假设当前队列分配的最大空间为6,填满,然后出队列4个,还剩2个位置时,不能在继续向队尾插入新元素,否则会因数组越界而导致程序代码被破坏。然而此时又不宜如顺序栈哪样,进行存储在分配扩大数组空间,因为队列的实际可用空间未被占满,一个巧妙的办法是将顺序队列臆造为一个环形的空间。

IMG_20190710_171051.jpg