• 栈:中缀表达式转后缀表达式(逆波兰式)求值(支持多位数)【C语言,数据结构】(内含源代码)


    目录

    题目:

    需求分析:

    概要设计:

    详细设计:

    3.转逆波兰表达式 

    4.逆波兰表达式求值

    总结:

     用户手册:

    测试结果:

     源代码:


    题目:

    设计并验证以下算法: 首先将一个中缀表达式转换成逆波兰式(后缀表达式),然后对此逆波兰表达式求值。

    需求分析:

    1.输入分析:可能输入正确的和错误的表达式,可能输入超过一位的数字,输入的表达式可能产生浮点类型的结果,输入中空格可能出现在任何地方,输入由‘#’结尾。(现只输入整数)

    2.演示程序在用户输入完整表达式后,若表达式不合法则输出相应提示,先输出用户表达式,再输出逆波兰表达式,最后输出其结果。

    3.程序执行命令包括:(1)接受输入 (2)判断输入 (3)求逆波兰式 (4)根据逆波兰式求值 

    4.测试数据:

    1. 1+1#
    2. 1+2*3-4/5#
    3. (4+2)*3-3/2#
    4. (4+2)*(8-2)/2#

    概要设计

    1.输入数据可以用数组存储,或者用顺序表存储,在本次实验用数组存储。

    2.判断与转换同时进行。数据处理部分,为了使程序更快,只用遍历一次原输入,所以在这里让判断正误与转逆波兰表达式同时进行。

    3.使用两种栈。在表达式转逆波兰表达式的时候需要用到栈来存储操作符,并且在使用逆波兰式表达式求值的时候也要用到栈来存储数,所以用要用两种栈来存储不同的数据类型。

    4.程序模块:

    (1)主程序模块:

    1. void main(){
    2. 初始化
    3. 接受输入
    4. 判断与转换
    5. 求值
    6. 输出
    7. 结束
    8. }

    详细设计:

    1.跳过空格。输入的数据和符号在用户看来,为了美观可能会添加空格,所以在我们转逆波兰表达式的时候要跳过空格来处理字符。

    2.空格隔开数。因为输入可能是多位数,在后缀表达式里,我们怎么区分一个数是否为多位数呢?我想到的方法是用空格来个开各个数,这样就能区分了。详细操作是,每当遇到操作符,代表上一个数已经遍历完毕,在表达式数组中存入空格,来分开数据。

    e9d0087bddec4baeb20fe03e20ef044f.gif

    3.转逆波兰表达式 

    算法是这样的,从头开始遍历输入,当遇到数,就直接存入顺序表中。遇到符号时,就进行特殊处理:

    当栈内元素为空的时候,直接存入:

    61934a87c1a046e08786a49120b7ca15.gif

     当栈内有元素的时候,特殊处理。具体为,栈内优先级低于该符号则存入栈内,栈内优先级高于该符号,则把栈内符号输出,继续比较栈内符号。(操作会直到栈内符号优先级高于它,或栈内为空的时候):

    845929017a83406188b969e12ad07192.gif

     f18216f3bb8e4f0a953327ede745d9c7.gif

    括号特殊处理。可以看做'('的优先级高于一切, ')'时,输出栈内元素,直到栈内上一个'('。

    遍历完所有后,清空栈内元素,当遍历完所有元素后,把栈内剩余的操作符全部出栈。

    对,就是这么简单。

    1. void GetPE(SqList L, SqList *PE) {
    2. //根据输入求后缀表达式,若输入错误则报错
    3. int f = 1; //判断输入工具
    4. int l = L.length;
    5. SqStack OP; //操作符栈
    6. char c;
    7. int s = 0;
    8. InitStack(&OP);
    9. if(L.elem[0] <= '9' && L.elem[0] >= '0') {
    10. f = 0;
    11. }
    12. for(int i = 0; i < l; i++) {
    13. if(L.elem[i] <= '9' && L.elem[i] >= '0') {
    14. f = 0;
    15. ListInsert_SqList(PE, -1, L.elem[i]);
    16. } else {
    17. if(L.elem[i] != '(' && L.elem[i] != ')') {
    18. if(i != 0 && f == 1) {
    19. printf("ERROR!");
    20. exit(ERROR);
    21. }
    22. f = 1;
    23. }
    24. if(L.elem[i] == '(') {
    25. Push(&OP, L.elem[i]);
    26. } else if(L.elem[i] == ')') {
    27. Pop(&OP, &c);
    28. while(c != '(') {
    29. ListInsert_SqList(PE, -1, c);
    30. Pop(&OP, &c);
    31. }
    32. } else if(L.elem[i] == '+' || L.elem[i] == '-') {
    33. s = GetTop(OP, &c);
    34. while(s != 0 && c != '(') {
    35. Pop(&OP, &c);
    36. ListInsert_SqList(PE, -1, c);
    37. s = GetTop(OP, &c);
    38. }
    39. Push(&OP, L.elem[i]);
    40. } else if(L.elem[i] == '/' || L.elem[i] == '*') {
    41. s = GetTop(OP, &c);
    42. while(s == 1 && (c == '*' || c == '/')) {
    43. Pop(&OP, &c);
    44. ListInsert_SqList(PE, -1, c);
    45. s = GetTop(OP, &c);
    46. }
    47. Push(&OP, L.elem[i]);
    48. }
    49. if(L.elem[i] != '(' && L.elem[i] != ')') {
    50. ListInsert_SqList(PE, -1, ' ');
    51. }
    52. }
    53. }
    54. s = GetTop(OP, &c); //判断并输出栈中剩余符号
    55. while(s) {
    56. Pop(&OP, &c);
    57. ListInsert_SqList(PE, -1, c);
    58. s = GetTop(OP, &c);
    59. }
    60. }

    4.逆波兰表达式求值

    逆波兰表达式的方法很简单,就是遇到符号就进行前两个数的计算,在入栈。

    不会的推荐这一篇文章。

    http://t.csdn.cn/yOqQN

    1. float GetPEResult(SqList L) {
    2. //根据后缀表达式求结果
    3. float sum = 0, tool2;
    4. int tool, flag;
    5. int l = L.length;
    6. SqStack2 PR; //数字栈
    7. InitStack2(&PR);
    8. for(int i = 0; i < l; i++) {
    9. tool = 0, flag = 0, tool2 = 0, sum = 0;
    10. while(L.elem[i] <= '9' && L.elem[i] >= '0') {
    11. tool = tool * 10;
    12. tool += L.elem[i] - '0';
    13. i++;
    14. flag = 1;
    15. }
    16. if(flag == 1) {
    17. Push2(&PR, (float)tool);
    18. }
    19. switch(L.elem[i]) {
    20. case '+':
    21. Pop2(&PR, &tool2);
    22. Pop2(&PR, &sum);
    23. Push2(&PR, tool2 + sum);
    24. break;
    25. case '-':
    26. Pop2(&PR, &tool2);
    27. Pop2(&PR, &sum);
    28. Push2(&PR, sum - tool2);
    29. break;
    30. case '*':
    31. Pop2(&PR, &tool2);
    32. Pop2(&PR, &sum);
    33. Push2(&PR, tool2 * sum);
    34. break;
    35. case '/':
    36. Pop2(&PR, &tool2);
    37. Pop2(&PR, &sum);
    38. Push2(&PR, sum / tool2);
    39. break;
    40. }
    41. }
    42. Pop2(&PR, &sum);
    43. return sum;
    44. }

    总结:

    这个程序还可以简化,在转逆波兰的时候,用到了很多if语句,还可以把操作符的优先级做成一张表格,通过表格来进行判断。

    e0bef80a575d41b38c3c6ebee504f817.png

     用户手册:

    1.本程序运行环境为DOS。

    2.输入表达式后#结束,回车

    3.根据输入,程序输出逆波兰表达式与结果。

    测试结果:

    64d29dea75b7413e8a03b6b994e8c557.png

     d3fef885f9e24e43b4b4295ab2049b25.png

     db4bb8be28984d6ab8204562214f1d07.png

     91318d614d51471fa8f216327da54027.png

     f6184bbf72f145468d511f40aaa5d10b.png

     源代码:

    主程序:

    1. #include "head.h"
    2. void Input(SqList * ); //把输入进行特殊处理后存入,#结束
    3. void GetPE(SqList, SqList *); //根据输入求后缀表达式,若输入错误则报错
    4. float GetPEResult(SqList); //根据后缀表达式求结果
    5. int main() {
    6. float answer;
    7. SqList input, PE; //初始化
    8. InitList_SqList(&input);
    9. InitList_SqList(&PE);
    10. printf("Please enter your expression and end with '#':\n");
    11. Input(&input); //把输入存入input中
    12. printf("Your input is: "); //输出原式
    13. printlist_SqList(input);
    14. GetPE(input, &PE); //输出逆波兰式
    15. printf("To RPExpression is: ");
    16. printlist_SqList(PE);
    17. answer = GetPEResult(PE);
    18. printf("Answer is: %.2lf", answer);
    19. return 0;
    20. }
    21. void Input(SqList *input) {
    22. //把输入进行特殊处理后存入,#结束
    23. ElemType c;
    24. while(1) {
    25. scanf(" %c", &c);
    26. if(c == '#') {
    27. break;
    28. }
    29. ListInsert_SqList(input, -1, c);
    30. }
    31. }
    32. void GetPE(SqList L, SqList *PE) {
    33. //根据输入求后缀表达式,若输入错误则报错
    34. int f = 1; //判断输入工具
    35. int l = L.length;
    36. SqStack OP; //操作符栈
    37. char c;
    38. int s = 0;
    39. InitStack(&OP);
    40. if(L.elem[0] <= '9' && L.elem[0] >= '0') {
    41. f = 0;
    42. }
    43. for(int i = 0; i < l; i++) {
    44. if(L.elem[i] <= '9' && L.elem[i] >= '0') {
    45. f = 0;
    46. ListInsert_SqList(PE, -1, L.elem[i]);
    47. } else {
    48. if(L.elem[i] != '(' && L.elem[i] != ')') {
    49. if(i != 0 && f == 1) {
    50. printf("ERROR!");
    51. exit(ERROR);
    52. }
    53. f = 1;
    54. }
    55. if(L.elem[i] == '(') {
    56. Push(&OP, L.elem[i]);
    57. } else if(L.elem[i] == ')') {
    58. Pop(&OP, &c);
    59. while(c != '(') {
    60. ListInsert_SqList(PE, -1, c);
    61. Pop(&OP, &c);
    62. }
    63. } else if(L.elem[i] == '+' || L.elem[i] == '-') {
    64. s = GetTop(OP, &c);
    65. while(s != 0 && c != '(') {
    66. Pop(&OP, &c);
    67. ListInsert_SqList(PE, -1, c);
    68. s = GetTop(OP, &c);
    69. }
    70. Push(&OP, L.elem[i]);
    71. } else if(L.elem[i] == '/' || L.elem[i] == '*') {
    72. s = GetTop(OP, &c);
    73. while(s == 1 && (c == '*' || c == '/')) {
    74. Pop(&OP, &c);
    75. ListInsert_SqList(PE, -1, c);
    76. s = GetTop(OP, &c);
    77. }
    78. Push(&OP, L.elem[i]);
    79. }
    80. if(L.elem[i] != '(' && L.elem[i] != ')') {
    81. ListInsert_SqList(PE, -1, ' ');
    82. }
    83. }
    84. }
    85. s = GetTop(OP, &c); //判断并输出栈中剩余符号
    86. while(s) {
    87. Pop(&OP, &c);
    88. ListInsert_SqList(PE, -1, c);
    89. s = GetTop(OP, &c);
    90. }
    91. }
    92. float GetPEResult(SqList L) {
    93. //根据后缀表达式求结果
    94. float sum = 0, tool2;
    95. int tool, flag;
    96. int l = L.length;
    97. SqStack2 PR; //数字栈
    98. InitStack2(&PR);
    99. for(int i = 0; i < l; i++) {
    100. tool = 0, flag = 0, tool2 = 0, sum = 0;
    101. while(L.elem[i] <= '9' && L.elem[i] >= '0') {
    102. tool = tool * 10;
    103. tool += L.elem[i] - '0';
    104. i++;
    105. flag = 1;
    106. }
    107. if(flag == 1) {
    108. Push2(&PR, (float)tool);
    109. }
    110. switch(L.elem[i]) {
    111. case '+':
    112. Pop2(&PR, &tool2);
    113. Pop2(&PR, &sum);
    114. Push2(&PR, tool2 + sum);
    115. break;
    116. case '-':
    117. Pop2(&PR, &tool2);
    118. Pop2(&PR, &sum);
    119. Push2(&PR, sum - tool2);
    120. break;
    121. case '*':
    122. Pop2(&PR, &tool2);
    123. Pop2(&PR, &sum);
    124. Push2(&PR, tool2 * sum);
    125. break;
    126. case '/':
    127. Pop2(&PR, &tool2);
    128. Pop2(&PR, &sum);
    129. Push2(&PR, sum / tool2);
    130. break;
    131. }
    132. }
    133. Pop2(&PR, &sum);
    134. return sum;
    135. }

    头文件:

    1. #include //头文件
    2. #include
    3. #include
    4. #include
    5. #include
    6. #define TRUE 1 //函数结果状态码
    7. #define FALSE 0
    8. #define ERROR 0
    9. #define OK 1
    10. #define EQUAL 1
    11. #define OVERFLOW -1
    12. #define INFEASIBLE -2
    13. #define STACK_INIT_SIZE 100 //存储空间初始分配量
    14. #define STACKINCREMENT 10 //存储空间分配增量
    15. #define LIST_INIT_SIZE 100 //顺序表存储空间的初始分配量
    16. #define LISTINCREMENT 10 //顺序表存储空间的分配增量
    17. typedef int Status; //Status 为函数返回值类型,其值为函数结果状态代码
    18. typedef char SElemType; //栈中数据元素类型为char型
    19. typedef float SElemType2; //栈中数据元素类型为float型
    20. typedef struct { //栈的顺序存储表示
    21. SElemType* base; //栈构造之前和销毁之后,其值为NULL
    22. SElemType* top; //栈顶指针
    23. int stacksize; //当前已分配的存储空间
    24. } SqStack;
    25. typedef struct { //栈的顺序存储表示
    26. SElemType2* base; //栈构造之前和销毁之后,其值为NULL
    27. SElemType2* top; //栈顶指针
    28. int stacksize; //当前已分配的存储空间
    29. } SqStack2;
    30. typedef char ElemType;//顺序表中数据元素类型
    31. struct LIST {
    32. ElemType* elem; //顺序表的存储空间基址
    33. int length; //当前长度
    34. int listsize; //当前分配的存储容量
    35. };
    36. typedef struct LIST SqList; //线性表的顺序存储结构定义
    37. Status InitStack(SqStack*); //栈初始化
    38. Status DestroyStack(SqStack*); //销毁栈
    39. Status StackEmpty(SqStack); //栈判空
    40. Status GetTop(SqStack, SElemType*); //取栈顶元素
    41. Status Push(SqStack*, SElemType); //入栈
    42. Status Pop(SqStack*, SElemType*); //出栈
    43. Status StackTraverse(SqStack); //遍历栈,输出每个数据元素
    44. Status InitList_SqList(SqList*); //构造一张新的顺序表L
    45. Status ListInsert_SqList(SqList*, int, ElemType ); //在顺序表L的第i个元素前插入新元素e
    46. int ListLength_SqList(SqList); //求顺序表L的长度
    47. Status Destroy_SqList(SqList*); //销毁一张顺序表
    48. void printlist_SqList(SqList); //输出顺序表
    49. Status InitStack2(SqStack2*); //栈初始化
    50. Status DestroyStack2(SqStack2*); //销毁栈
    51. Status StackEmpty2(SqStack2); //栈判空
    52. Status GetTop2(SqStack2, SElemType2*); //取栈顶元素
    53. Status Push2(SqStack2*, SElemType2); //入栈
    54. Status Pop2(SqStack2*, SElemType2*); //出栈
    55. Status StackTraverse2(SqStack2); //遍历栈,输出每个数据元素
    56. Status InitStack(SqStack* S) {
    57. //构造一个空栈Ss
    58. S->base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
    59. if(!S->base) {
    60. //存储分配失败
    61. exit(OVERFLOW);
    62. }
    63. S->top = S->base;
    64. S->stacksize = STACK_INIT_SIZE;
    65. return OK;
    66. }//InitStack
    67. Status GetTop(SqStack S, SElemType* e) {
    68. //若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
    69. if(S.top == S.base) {
    70. return ERROR;
    71. }
    72. *e = *(S.top - 1);
    73. return OK;
    74. }//GetTop
    75. Status Push(SqStack* S, SElemType e) {
    76. //插入元素e为新的栈顶元素
    77. if(S->top - S->base >= S->stacksize) {
    78. //栈满,追加存储空间
    79. S->base = (SElemType*)realloc(S->base, (S->stacksize + STACKINCREMENT) * sizeof(SElemType));
    80. if(!S->base) {
    81. //存储分配失败
    82. exit(OVERFLOW);
    83. }
    84. S->top = S->base + S->stacksize;
    85. S->stacksize += STACKINCREMENT;
    86. }
    87. *S->top++ = e;
    88. return OK;
    89. }//Push
    90. Status Pop(SqStack* S, SElemType* e) {
    91. //若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROE
    92. if(S->top == S->base) {
    93. return ERROR;
    94. }
    95. *e = *(--S->top);
    96. return OK;
    97. }//Pop
    98. Status DestoryStack(SqStack* S) {
    99. //销毁栈S
    100. if(S->base) {
    101. free(S->base);
    102. }
    103. S->top = S->base = NULL;
    104. return OK;
    105. }//DestroyStack
    106. Status StackTraverse(SqStack S) {
    107. //遍历栈,输出每一个数据元素
    108. SElemType* p = S.base;
    109. int i = 0;
    110. if(S.base == S.top) {
    111. printf("Stack is Empty.\n");
    112. return OK;
    113. }
    114. while(p < S.top) {
    115. printf("[%d:%c]", ++i, *p++);
    116. }
    117. printf("\n");
    118. return OK;
    119. }//StackTraverse
    120. Status InitStack2(SqStack2* S) {
    121. //构造一个空栈Ss
    122. S->base = (SElemType2*)malloc(STACK_INIT_SIZE * sizeof(SElemType2));
    123. if(!S->base) {
    124. //存储分配失败
    125. exit(OVERFLOW);
    126. }
    127. S->top = S->base;
    128. S->stacksize = STACK_INIT_SIZE;
    129. return OK;
    130. }//InitStack
    131. Status GetTop2(SqStack2 S, SElemType2* e) {
    132. //若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
    133. if(S.top == S.base) {
    134. return ERROR;
    135. }
    136. *e = *(S.top - 1);
    137. return OK;
    138. }//GetTop
    139. Status Push2(SqStack2* S, SElemType2 e) {
    140. //插入元素e为新的栈顶元素
    141. if(S->top - S->base >= S->stacksize) {
    142. //栈满,追加存储空间
    143. S->base = (SElemType2*)realloc(S->base, (S->stacksize + STACKINCREMENT) * sizeof(SElemType2));
    144. if(!S->base) {
    145. //存储分配失败
    146. exit(OVERFLOW);
    147. }
    148. S->top = S->base + S->stacksize;
    149. S->stacksize += STACKINCREMENT;
    150. }
    151. *S->top++ = e;
    152. return OK;
    153. }//Push
    154. Status Pop2(SqStack2* S, SElemType2* e) {
    155. //若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROE
    156. if(S->top == S->base) {
    157. return ERROR;
    158. }
    159. *e = *(--S->top);
    160. return OK;
    161. }//Pop
    162. Status DestoryStack2(SqStack2* S) {
    163. //销毁栈S
    164. if(S->base) {
    165. free(S->base);
    166. }
    167. S->top = S->base = NULL;
    168. return OK;
    169. }//DestroyStack
    170. Status StackTraverse2(SqStack2 S) {
    171. //遍历栈,输出每一个数据元素
    172. SElemType2* p = S.base;
    173. int i = 0;
    174. if(S.base == S.top) {
    175. printf("Stack is Empty.\n");
    176. return OK;
    177. }
    178. while(p < S.top) {
    179. printf("[%d:%.2lf]", ++i, *p++);
    180. }
    181. printf("\n");
    182. return OK;
    183. }//StackTraverse
    184. Status InitList_SqList(SqList* L) { //构造一个空顺序表L
    185. L->elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType)); //分配内存
    186. if(!L->elem)
    187. exit(OVERFLOW);
    188. L->length = 0;
    189. L->listsize = LIST_INIT_SIZE;
    190. return OK;
    191. } //InitList_SqList
    192. Status ListInsert_SqList(SqList* L, int i, ElemType e) { //在顺序表L的第i个元素前插入新元素e
    193. ElemType* newbase, *p, *q;
    194. if(i == -1) {
    195. i = L->length + 1;
    196. }
    197. if(i < 1 || i > L->length + 1)
    198. return ERROR; //插入位置不合法
    199. if(L->length >= L->listsize) { //当前存储空间已满,增加分配
    200. newbase = (ElemType*)realloc(L->elem, (L->listsize + LISTINCREMENT) * sizeof(ElemType));
    201. if(!newbase)
    202. return ERROR; //存储分配失败
    203. L->elem = newbase; //新基址
    204. L->listsize += LISTINCREMENT; //增加存储容量
    205. }
    206. q = &(L->elem[i - 1]); //q指向插入位置
    207. for(p = &L->elem[L->length - 1]; p >= q; --p)
    208. *(p + 1) = *p; //插入位置之后的数据元素右移
    209. *q = e; //插入e
    210. L->length++;
    211. return OK;
    212. } //ListInsert_SqList
    213. int ListLength_SqList(SqList L) { //求顺序表L的长度
    214. return L.length;
    215. } //ListLength_SqList;
    216. Status Destroy_SqList(SqList* L) { //销毁一张顺序表
    217. free(L);
    218. return OK;
    219. } //Destroy_SqList
    220. void printlist_SqList(SqList L) { //输出顺序表
    221. int i;
    222. for(i = 0; i < L.length; i++)
    223. printf("%c", L.elem[i]);
    224. printf("\n");
    225. } //printlist_SqList;

  • 相关阅读:
    使用 python multiprocessing.Queue 出现 too many open files 错误
    java计算机毕业设计ssm智能水务管理系统
    MySQL数据去重
    文心一言 VS 讯飞星火 VS chatgpt (97)-- 算法导论9.3 3题
    【六、http】go的http的客户端重定向
    二、nginx URL重写[rewrite]
    从过滤器初识责任链设计模式
    SpringCloud微服务(三)——Zookeeper服务注册中心
    1、Netty适合场景
    ElasticSearch 搜索推荐
  • 原文地址:https://blog.csdn.net/qq_62792553/article/details/127595117