NYOJ-467 中缀式变后缀式【逆波兰法】

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=467

解题思路:

经典的逆波兰法求表达式的值,以前是用栈模拟的,但是没有仔细研究,现在对表达式求值方法有了一定的了解。

其实表达式求值的通法就是建立一棵表达式树,则,前缀、中缀、后缀表达式分别对应表达式树的前序、中序、后序遍历。

则,通过表达式树就可以对这个问题做一个全面的分析了。另外还有一种方法是基于编译原理的自顶向下分析的方法,还没有研究,等研究好了再重新写吧。

相关知识可以点这里:

逆波兰表示法:http://zh.wikipedia.org/wiki/%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E7%A4%BA%E6%B3%95#.E8.A7.A3.E9.87.8A

中缀转后缀法:http://zh.wikipedia.org/wiki/Shunting_yard%E7%AE%97%E6%B3%95

代码如下:

/*
*表达式求值的经典算法
*编写代码对算术表达式求值的经典方法由 Donald Knuth 描述于 1962 年。
*
*Knuth 将此概括为三个步骤:
*1、对中缀表达式进行语法分析
*2、中缀表达式到后缀表达式的转换
*3、对后缀表达式求值
*
*注意到我们谈到的这个经典算法有些简化:算术表达式只包含操作数、二元操作符和一种括号。
*此外,对于每个操作数和操作符,只用单个字符表示,使语法分析直观。
*表达式表示法:
*算术表达式中最常见的表示法形式有 中缀、前缀和 后缀表示法。
*中缀表示法是书写表达式的常见方式,而前缀和后缀表示法主要用于计算机科学领域。
*
*中缀表示法:
*中缀表示法是算术表达式的常规表示法。称它为中缀表示法是因为每个操作符都位于
*其操作数的中间,这种表示法只适用于操作符恰好对应两个操作数的时候
*(在操作符是二元操作符如加、减、乘、除以及取模的情况下)。
*对以中缀表示法书写的表达式进行语法分析时,需要用括号和优先规则排除多义性。
*Syntax: operand1 operator operand2
*Example: (A+B)*C-D/(E+F)

* 前缀表示法 
*		 前缀表示法中,操作符写在操作数的前面。这种表示法经常用于计算机科学,
*     	 特别是编译器设计方面。为纪念其发明家 ― Jan Lukasiewicz,
*		 这种表示法也称 波兰表示法。
*Syntax  : operator operand1 operand2
*Example : -*+ABC/D+EF
*
*后缀表示法 
*		  在后缀表示法中,操作符位于操作数后面。后缀表示法也称 逆波兰表示法
*		 (reverse Polish notation,RPN),因其使表达式求值变得轻松,所以被普遍使用。
*Syntax  : operand1 operand2 operator
*Example : AB+C*DEF+/-
*前缀和后缀表示法有三项公共特征:
*操作数的顺序与等价的中缀表达式中操作数的顺序一致
*不需要括号
*操作符的优先级不相关
*
*中缀转化为后缀算法: 
*a.得到一操作符或操作数; 
*b.若输入为操作数,则输出到数组,转a; 
*c.	若输入为'(',压栈,转a; 
*d.若输入为')',栈顶出栈,输出到数组,直至栈顶为'(',抛弃'(', 转a; 
*e.若输入为操作符, 
*		若栈空或栈顶为'('或操作符.忧先级大于栈顶操作符,压栈,转a 
*		若操作符优先级小于栈顶操作符,则出栈,输出至数组,转e; 
*d.若输入结束,出栈,输出到数组,直至栈空。 
*数组SNode中即为后缀表达式; 
*
*优先级可以根据需要分为:栈内优先级和栈外优先级 
*
*后缀表达式求值
*对后缀表达式求值比直接对中缀表达式求值简单。在后缀表达式中,不需要括号,
*而且操作符的优先级也不再起作用了。您可以用如下算法对后缀表达式求值:初始化一个空堆栈
*从左到右读入后缀表达式,如果字符是一个操作数,把它压入堆栈。如果字符是个操作符,
*弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,
*后缀表达式的语法就不正确。到后缀表达式末尾,从堆栈中弹出结果。
*若后缀表达式格式正确,那么堆栈应该为空。
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<climits>
#include<vector>
#include<stdlib.h>
#include<algorithm>
using namespace std;

const int N = 1010;
char str[N];
vector<double> num; //操作数
vector<char>ope; //运算符

int judge_oper(const char ch) //运算符优先级
{
	switch(ch)
	{
	case '=' : return 1;
	case '+' : return 2;
	case '-'  : return 2;
	case '*'  : return 3;
	case '/'  : return 3;
	case '('  : return 0;
	case ')'  : return 0;
	};
}

int main()
{
	int ncase;
	scanf("%d", &ncase);

	int len; //字符串长度
	double temp; //字符串中提取操作数
	int length; //操作数位数

	while(ncase--)
	{
		memset(str, '\0', sizeof(str));
		num.clear();
		ope.clear();
		ope.push_back('=');
		getchar();
		scanf("%s", str);
		len = strlen(str) - 1;
		for(int i = 0; i < len; ++i)
		{
			if(str[i] >= '0' && str[i] <= '9') //操作数
			{
				sscanf(&str[i], "%lf%n", &temp, &length);
				num.push_back(temp);
				for(int j = i; j < i + length; ++j)
					printf("%c", str[j]);
				printf(" ");
				i += length - 1;
			}
			else //运算符
			{
				if(str[i] == '(' || judge_oper(str[i]) > judge_oper(ope.back()))
					ope.push_back(str[i]);
				else
				{
					if(str[i] == ')')
					{
						while(ope.back() != '(')
						{
							printf("%c ", ope.back());
							ope.pop_back();
						}
						ope.pop_back();
					}
					else
					{
						while( judge_oper(str[i]) <= judge_oper( ope.back() ) && ope.back() != '(')
						{
							printf("%c ", ope.back());
							ope.pop_back();
						}
						ope.push_back(str[i]);
					}
				}
			}
		}
		while(!ope.empty())
		{
			printf("%c ", ope.back());
			ope.pop_back();
		}
		printf("\n");
	}
	return 0;
}


孪生素数是指两个素数之间的差值为2的素数对。通过筛选可以找出给定素数范围内的所有孪生素数的组数。 在引用的代码中,使用了递归筛选来解决孪生素数问题。该程序首先使用循环将素数的倍数标记为非素数,然后再遍历素数数组,找出相邻素数之间差值为2的素数对,并统计总数。 具体实现过程如下: 1. 定义一个数组a[N,用来标记数字是否为素数,其中N为素数范围的上限。 2. 初始化数组a,将0和1标记为非素数。 3. 输入要查询的孪生素数的个数n。 4. 循环n次,每次读入一个要查询的素数范围num。 5. 使用两层循环,外层循环从2遍历到num/2,内层循环从i的平方开始,将素数的倍数标记为非素数。 6. 再次循环遍历素数数组,找出相邻素数之间差值为2的素数对,并统计总数。 7. 输出总数。 至此,我们可以使用这个筛选的程序来解决孪生素数问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python用递归筛选求N以内的孪生质数(孪生素数)](https://blog.csdn.net/weixin_39734646/article/details/110990629)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [NYOJ-26 孪生素数问题](https://blog.csdn.net/memoryofyck/article/details/52059096)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值