在之前的文章中,我介绍了“打擂台”算法。“打擂台”算法一般用于求最大值或者最小值问题。如果您还不了解它的规则,请先看我的这篇文章。

在“打擂台”算法中,擂主的初值一般是设成待处理数据的第一个数,这也是我推荐大家在解答编程题时使用的方法。但在GESP考试以及其他竞赛中,除了编程题,还有单选题和判断题,在这些题目中,出题者就不一定采用“第一个数作为擂主”的方法,而是采用另外一种方法——极值法,即先把擂主设成某个极值。

我们先来看一道判断题真题:下列代码能正确输出数组中的最小值2。

int main() {
	int array[5] = {3, 7, 5, 2, 4};
	int min = 0;
	for (int i=0; i<5; i++)
	{	
		if (array[i] < min)
			min = array[i];
	}
	cout << min << endl;
	return 0;
}

分析:这段代码使用了擂台法求最小值,但擂主的初值设成了0。虽然循环中“打擂”的逻辑是对的,但由于所有要判断的数都大于0,所以所有打擂都失败了,最后的结果为初值0,不是数组中的最小值。所以这道题的答案是错误。

这就是使用极值法时一个极其需要注意的地方:要求最小值时,要先把擂主设成一个尽量大的值。反过来,要求最大值时,要先把擂主设成一个尽量小的值。

具体到本题中,数组元素的类型为int,所以要把min的初值设成int型数的最大值,即2147483647。而如果要求最大值,则要把擂主的初值设成int型数的最小值-2147483648(注意不是-2147483647)。

由此可见,使用极值法时,对于最大值和最小值,初值要设成不同的极值,这已经容易产生混淆了,而记住极值是一件更加困难的事,很多初学者根本记不住int型数的两个极值。所以,笔者强烈建议:解答编程题时,尽量使用第一个值作为擂主的初值。

具体到本题,可以这样修改代码:

//擂台法求数组的最小值 
int main() {
	int array[5] = {3, 7, 5, 2, 4};
	int min = array[0];			//擂主先设为第一个数 
	for (int i=1; i<5; i++)		//循环从第二个数开始 
	{	
		if (array[i] < min)
			min = array[i];
	}
	cout << min << endl;
	return 0;
}

如果要求最大值,只需修改一个符号(变量名的修改非必须):

//擂台法求数组的最大值 
int main() {
	int array[5] = {3, 7, 5, 2, 4};
	int max = array[0];			//擂主先设为第一个数 
	for (int i=1; i<5; i++)		//循环从第二个数开始 
	{	
		if (array[i] > max)		//此处把<改成>
			max = array[i];
	}
	cout << max << endl;
	return 0;
}

这里需要注意的是,使用第一个数作为擂主时,循环必须从第二个数开始。虽然在本题中,循环从第一个数开始也不会有错(第一个数挑战自己一定失败),但在有些情况下,循环从第一个数开始就不对了。

例如,待处理的数据需要从屏幕或者文件读入(这也是通常的情况),此时先读入第一个数并设为擂主。如果接下来循环仍然从第一个数开始,那么第一个数要被读入两次,结果是数据不够。以下代码是错误的:

//错误的写法 
int main() {
	int n, a, min;
	cin >> n >> a;			    //读入n和第一个数
	min = a;					//擂主先设为第一个数 
	for (int i=0; i<n; i++)		//循环从第一个数开始,第一个数读了两次,导致数据不够 
	{	
		cin >> a;
		if (a < min)
			min = a;
	}
	cout << min << endl;
	return 0;
}

此时,循环一定要从第二个数开始。

本文为学漄乐码堂主撰写。堂主已出版《GESP直通车——C++精简讲练》系列,一级到五级。

如果您想要学到真正的知识,而不只是应试的技巧,欢迎留言跟我联系。

(写作不易,请大家点赞、关注、收藏、转发!)

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐