Skip to content

Commit 21cf275

Browse files
中缀表达式转后缀表达式初稿
1 parent bea3be0 commit 21cf275

File tree

11 files changed

+879
-2
lines changed

11 files changed

+879
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
## 阅读书籍列表
44
- [x] 大话设计模式/程杰 著. --北京:清华大学出版社,2007.12(2018.5 重印)
55
- [ ] 大话设计模式/程杰 著. --北京:清华大学出版社,2011.6(2018.8 重印)
6+
<!--- [ ] [airbnb/javascript](https://github.com/airbnb/javascript)([中文翻译](https://github.com/lin-123/javascript))-->

da-hua-shu-ju-jie-gou/04-stack/README.md

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,121 @@ void FibonacciTest(void) {
171171
**把一个直接调用自己或通过一系列的调用语句间接的调用自己的函数,称为递归函数**
172172
**每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身而是返回值退出**
173173
174-
<!--## 栈的应用 -- 四则运算表达式求值-->
175-
<!--### 后缀(逆波兰)表示法定义-->
174+
## 栈的应用 -- 四则运算表达式求值-->
175+
### 后缀(逆波兰)表示法定义
176+
**所有操作符置于操作数的后面 也称 后缀表示法**
177+
> 逆波兰记法中,操作符置于操作数的后面。例如表达“三加四”时,写作“3 4 +”,而不是“3 + 4”。如果有多个操作符,操作符置于第二个操作数的后面,所以常规中缀记法的“3 - 4 + 5”在逆波兰记法中写作“3 4 - 5 +”:先3减去4,再加上5。使用逆波兰记法的一个好处是不需要使用括号。例如中缀记法中“3 - 4 * 5”与”(3 - 4)* 5” 不相同,但后缀记法中前者写做“3 4 5 * -”,无歧义地表示“3 (4 5 * ) -”;后者写做“3 4 - 5 * ” --- [摘自维基百科](https://zh.wikipedia.org/wiki/%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E7%A4%BA%E6%B3%95)
176178
179+
以大化数据结构中的例子 9 + ( 3 - 1 ) * 3 + 10 / 2, 其逆波兰表示为 (9 ((3 1 -) 3 *)+) (10 2 /) + 即 **9 3 1 - 3 * + 10 2 / +**
180+
181+
### 中缀表达式转后缀表达式
182+
```c
183+
/**
184+
转换中缀表达式为后缀表达式
185+
186+
@param expression 中缀表达式 如:9+(3-1)*3+4/2
187+
@param rpn 得到的后缀表达式
188+
@return 转换状态, 是否成功
189+
*/
190+
Status transferExpressionToRPN(const char *expression, char *rpn) {
191+
192+
LinkStack stack;
193+
InitLinkStack(&stack);
194+
195+
// char realExp[MAXSIZE];
196+
// convertExpression(expression, realExp);
197+
198+
char result[MAXSIZE];
199+
int cur = 0;
200+
201+
for (int i=0; i<MAXSIZE; i++) {
202+
char one = expression[i];
203+
if('\0' == one) break;
204+
printf("%c\n", one);
205+
// 如果是数字, 直接输出
206+
if (isdigit(one)) {
207+
if (cur != 0) {
208+
result[cur++] = ' ';
209+
}
210+
result[cur++] = one;
211+
continue;
212+
}
213+
214+
// 如果是符号
215+
// 遇到右括号出栈匹配左括号
216+
if (')' == one) {
217+
char e;
218+
Status s = LinkStackGetTop(&stack, &e);
219+
if (!s) return s;
220+
221+
while ('(' != e && !LinkStackEmpty(stack)) {
222+
s = LinkStackPop(&stack, &e);
223+
if ('(' != e) {
224+
result[cur++] = ' ';
225+
result[cur++] = e;
226+
}
227+
}
228+
continue;
229+
}
230+
// 如果是空栈或者 ( 直接入栈
231+
if (LinkStackEmpty(stack) || '(' == one) {
232+
LinkStackPush(&stack, one);
233+
continue;
234+
}
235+
236+
// 当前符号优先级比栈顶符号优先级高,则入栈, 否则出栈
237+
int pOne = getPriorityOfOperation(one);
238+
char e;
239+
LinkStackGetTop(&stack, &e);
240+
int pTop = getPriorityOfOperation(e);
241+
242+
// 符号优先级比栈顶符号高,则入栈, 否则出栈
243+
if (pOne > pTop || '(' == e) {
244+
LinkStackPush(&stack, one);
245+
continue;
246+
}
247+
248+
// 直到栈顶优先级比当前优先级高,或者栈空, 才停止出栈, 然后将当前符号入栈
249+
while (pTop > pOne || !LinkStackEmpty(stack)) {
250+
LinkStackPop(&stack, &e);
251+
pTop = getPriorityOfOperation(e);
252+
result[cur++] = ' ';
253+
result[cur++] = e;
254+
}
255+
LinkStackPush(&stack, one);
256+
}
257+
258+
// 循环结束, 将栈中剩余符号取出并输出
259+
while (!LinkStackEmpty(stack)) {
260+
char e;
261+
Status s = LinkStackPop(&stack, &e);
262+
if (!s) return s;
263+
result[cur++] = ' ';
264+
result[cur++] = e;
265+
}
266+
result[cur] = '\0';
267+
*rpn = result;
268+
printf("RPN: %s\n", result);
269+
return OK;
270+
}
271+
272+
/**
273+
获取运算符的优先级
274+
275+
@param op 运算符, 仅支持 + - * / ( )
276+
@return 优先级, 不支持的参数返回 - 1
277+
*/
278+
int getPriorityOfOperation(char op) {
279+
280+
if ('+' == op || '-' == op) {
281+
return 0; // 最低优先级
282+
}
283+
if('*' == op || '/' == op) {
284+
return 1; // 优先级比+- 高
285+
}
286+
if ('(' == op || ')' == op) {
287+
return 2; // 优先级比 */高
288+
}
289+
return -1;
290+
}
291+
```

0 commit comments

Comments
 (0)