两位数值单词的乘法实现

博主在前一个月参加了BIT计算机学院的夏令营活动,考试环节有机试和面试,其中机试有两道题。当时我正在做一个unity3D的赛车项目,每天愉快地写着C#,调着各种库,近两年来对于C语言的接触又仅限于做图形学和OpenGL作业,很多基础慢慢生疏了,于是机试上来第一题就看蒙了。

回来以后由于考研保研考试的缘故,从头学习C语言,使用的是Brain W.Kernighan和Dennis M.Ritchie所著的《The C Programming Language》原书,不得不说这本书比起谭版的教材更贴近语言本身,所选取的程序很完整,习题也很不错,重要的是把整个C语言的学习分成了基础、操作符和表达式、控制流、函数、输入输出流这样的模块,我个人更喜欢这样的分类法,因为它贴近于编程的实践过程。

闲言少叙,下面就上题目(回忆版)。

 

编程实现:用英文单词zero、one、two…分别表示0~99内其所对应的数字(如six表示6,one two表示12),实现两位数的乘法,输出乘积。

输入:two one * three * four

输出:252

 

读者在往下看之前不妨先思考一下能否构思出比较完整的框架:比如不限于两位数,能适应于多位数,可以从乘法轻松扩展到四则运算等等。这个题目重点考察的是输入以及控制流方面的能力,在回顾完控制流这一章后,再来看这个题目就非常的清楚。

首先,对于输入,我们假设输入无误,那么输入的都是空格、数值单词和乘号,并且总是数值单词位于输入的最末端。从输入类型来看,我们首先要判别的是三类的输入:空格、单词、乘号。这三者中空格是无效信息,因为它既可能处于数值之间(对于两位数的情况)也有可能处于数值和乘号之间,因此我们可以在一开始就把它当做无效信息通过判断语句消除。

其次,对于单词和乘号,很明显乘号是一个标志,它隔断了前后的两个数字,而我一开始考虑到的方法有1、每出现一次乘号就做一次乘法 2、使用栈来把前后两个数字分别压进去,当出现下一个乘号或者输入结束的时候对栈内的两个数字弹出并做乘积

这篇文章里面我使用的是第一种方法,但是我还是想叙述一下第二种方法的思路,因为第二种方法可以扩展出更多的符号运算。

首先建立两个栈:一个数字栈,一个符号栈。数字栈中的元素类型是字符数组,符号栈中的元素类型是字符。用一个足够长的字符数组input承载输入,每当出现一次乘号以后,首先检查符号栈中是否有乘号,若无则乘号入符号栈,input中的内容进数字栈;若有,则弹出数字栈中数字,与当前input中的数字做乘法,之后把符号栈中的乘号弹出。这样的过程需要首先建栈,之后为栈写初始化、获取顶部元素、入栈、出栈等方法,这些内容在数据结构中都有涉及,这里就不多说了,这里还会有一个关于把单词数字化的过程,我会在下文进行讨论。

我们回到第一种方法:每出现一次乘号就做一次乘法。这种方法从整体构思上来说并不难,但要考虑到如何使得整个过程完整地循环起来,首先遇到一个称号就做一次乘法,那么对于第一个出现的数值来说我们可以把它算作是总量的初始值,那么之后的每一个数字只需要对它进行累乘,这是很直观的,但坏处在于我们需要在输入的循环中添加赋初始值的判断语句;我们也可以把初始值的初值设为1,这样的话就可以把包括第一项的所有输入等同起来,正如我代码所写的:

	char c;
	//number数组接收输入的单词
	char numbers[LONGNUM];
	//mul为累乘结果
	int mul = 1,pos=0;
	while((c=getchar())!=EOF)
	{
		//忽略输入中的空格
		if(c != ' ')
			//出现乘号和回车都需要进行累乘
			if (c == '*' || c == '\n')
			{
				//加上结束符
				numbers[pos] = '\0';
				mul *= checknum(numbers);
				pos = 0;
			}
			else if(c >= 'a' && c <= 'z' && pos < LONGNUM)
			{
				numbers[pos] = c;
				pos ++;
			}
	}

整个方法的主要流程已经在这段代码中体现出来,在while控制的输入循环中:我们忽略空格;number数组接收输入的数字,每当有字母输入时使字母覆盖pos所对应的数组位置;当出现标志*和回车时结束当前输入(数组结尾加上结束符),用checknum函数返回数组中所对应的数字并累乘,把pos归零。

整个过程应该是比较清晰的,最后我们来讨论一下转换单词的checknum函数。对于数组number中的字符串来说,有可能是一位数也可能是两位数,而0~9的所有单词中最长的是5个字符,因此我们考虑把数组初始长度LONGNUM设为12(或以上)。

之后是识别字符的问题,在本文中我使用的是switch语句,我们可以观察one;two、three;four、five;six、seven;eight;nine;zero被分号隔开的都是单个单词或者首字母相同的两个单词,这是处理对象的固有特质,因此用switch语句先把它们分组相信能使得代码更简短一些。

int checknum(char num[])
{
	//Snumber为将要返回的字符串值
	int Snumber = 0,i = 0;
	for(int j = 0;i<LONGNUM && num[i]!= '\0';j++)	//没有到达数组边界且没有检测到结束符时
	{
		switch (num[i])
		{
			case 'o':
				if(num[i+1] == 'n' && num[i+2] == 'e')
				{
					Snumber = 10*Snumber + 1;
					i += 3;
					break;
				}
			case 't':
				if(num[i+1] == 'w' && num[i+2] == 'o')
				{
					Snumber = 10*Snumber + 2;
					i += 3;
					break;
				}
				else if(num[i+1] == 'h' && num[i+2] == 'r' && num[i+3] == 'e' && num[i+4] == 'e')
				{
					Snumber = 10*Snumber + 3;
					i += 5;
					break;
				}
			case 'f':
				if(num[i+1] == 'o' && num[i+2] == 'u' && num[i+3] == 'r')
				{
					Snumber = 10*Snumber + 4;
					i += 4;
					break;
				}
				else if(num[i+1] == 'i' && num[i+2] == 'v' && num[i+3] == 'e')
				{
					Snumber = 10*Snumber + 5;
					i += 4;
					break;
				}
			case 's':
				if(num[i+1] == 'i' && num[i+2] == 'x')
				{
					Snumber = 10*Snumber + 6;
					i += 3;
					break;
				}
				else if(num[i+1] == 'e' && num[i+2] == 'v' && num[i+3] == 'e' && num[i+4] == 'n')
				{
					Snumber = 10*Snumber + 7;
					i += 5;
					break;
				}
			case 'e':
				if(num[i+1] == 'i' && num[i+2] == 'g' && num[i+3] == 'h' && num[i+4] == 't')
				{
					Snumber = 10*Snumber + 8;
					i += 5;
					break;
				}
			case 'n':
				if(num[i+1] == 'i' && num[i+2] == 'n' && num[i+3] == 'e')
				{
					Snumber = 10*Snumber + 9;
					i += 4;
					break;
				}
			case 'z':
				if(num[i+1] == 'e' && num[i+2] == 'r' && num[i+3] == 'o')
				{
					Snumber = 10*Snumber + 0;
					i += 4;
					break;
				}
			default:
				printf("wrong number enter!\n");
		}
	}
	return Snumber;
}

结合注释是很容易理解的,处理数位的方法是把现有值Snumber*10加上当前输入值。这个函数不仅适用于两位数,也可以适用于更多位数。

下面贴三组运行数据,其中第三组有输入错误





 欢迎各位的交流和指教

源码:http://git.oschina.net/YiBuXuLong/codes/iu1zyj2oaxb59k4ltdf3g55

发布了8 篇原创文章 · 获赞 6 · 访问量 5559

猜你喜欢

转载自blog.csdn.net/longroad1216/article/details/77662634