[英]C++ Condense Two for-loops to Improve Efficiency
我需要从中检索数据的结构体数组。 该数组包含名称和分数。
对于一项功能,我必须输出最高分数和相关名称。 如果有多种情况,我必须输出所有名称。
我不能使用矢量或列表。 (否则,我只想在同一步骤中执行这两项操作。
这就是我的处理方式:
void highScorer ( player array[], int size )
{ // highScorer
int highScore = 0; //variable to hold the total score
// first loop determines highest score
for ( int i = 0; i < size; i++ ) {
if ( array[i].pointsScored > highScore ) {
highScore = array[i].pointsScored;
}
}
cout << "\nThe highest scoring player(s) were:\n";
// second loop finds players with scores matching highScore and prints their name(s)
for ( int i = 0; i < size; i++ ) {
// when a match is found, the players name is printed out
if ( array[i].pointsScored == highScore ) {
cout << array[i].playerName;
cout << ", scored ";
// conditional will output correct grammar
if ( array[i].pointsScored > 1 ) {
cout << array[i].pointsScored << " points!\n";
}
else {
cout << array[i].pointsScored << " point!\n";
}
}
}
cout << "\n"; // add new line for readability
return;
} // highScorer
我想将其浓缩为一个for循环。 除非有人建议使用一种更有效的方法。 我认为整理数据是不必要的。 另外,如果将其排序,那么如何一步就能确定是否有多个“ highScore”案例。
除了highScore
变量之外,您highScore
创建第二个变量,例如std::list
(或手动链接列表,甚至是一个小的数组,具体取决于允许使用的变量)。 在此列表中,您可以跟踪实际拥有当前高分的人的指数。 如果找到新的高分,则清除该列表并添加具有新高分的人。 如果发现某人的得分最高,您只需将其添加到列表中。
然后在循环之后,您只需要打印具有此列表中索引的播放器,而无需再次查找谁拥有最高分。
一种解决方案是在搜索高分时记录玩家的姓名。 如果它等于当前的最高分,则将一个附加名称附加到“名称集合字符串”中,如果更高,则将名称空白,并记录新的高分和新名称。 我ostringstream
名称的打印输出实现为ostringstream
以确保您不会在缓冲区上运行。 然后,完成后,打印出一组名称。
只要您经过第一(唯一)遍,就应保留得分最高的索引集。 然后,完成后,您将已经拥有与该最高分数相对应的一组索引。 用我刚刚编写的语言的伪代码:
int highestSoFar = 0;
list indexesOfHighScore = new list();
for (int i = 0; i < scores.count; i++) {
if (scores[i] > highestSoFar) {
highestSoFar = scores[i];
indexesOfHighScore.empty();
}
if (scores[i] == highestSoFar) {
indexesOfHighScore.add(i);
}
}
// Now I know the highest score, and all the indexes of entries that correspond to it.
如果没有可用的动态列表,则该列表可以是与scores数组大小相同的静态数组,以确保其始终足够大。
现在,您的第一个循环是跟踪高分。 如果它还跟踪所有匹配的名称,则可以在循环结束时输出名称。 您仍然需要第二个循环来遍历这些名称,这是不可避免的。
只需少量的存储成本,您就可以在同一遍中计算出高分和各个玩家:
player ** highScorer ( player array[], int size )
{
player ** result = new player*[size + 1]; // The +1 handles the case where everyone ties
int highScore = 0;
int foundAt = 0;
for ( int i = 0; i < size; i++ )
{
if ( array[i].pointsScored > highScore )
{
highScore = array[i].pointsScored;
foundAt = 0;
}
if ( array[i].pointsScored == highScore )
{
result[foundAt] = &(array[i]);
foundAt++;
}
}
result[foundAt] = null; // Stopping condition, hence the +1 earlier
return result; // Remember to delete[] the resulting array
}
然而。
那不会给你输出。 如果要输出结果,您仍然需要第二个循环。
void outputScores ( player ** result )
{
cout << "\nThe highest scoring player(s) were:\n";
for ( int i = 0; result[i] != null; i++ )
{
cout << result[i]->playerName;
cout << ", scored ";
if ( result[i]->pointsScored == 1 )
cout << "1 point!\n";
else
cout << result[i]->pointsScored << " points!\n";
}
cout << "\n";
delete [] result;
}
要回答您最初的问题,我认为没有任何方法可以在一个循环中找到并输出所有得分较高的球员。 即使对分数数组进行预排序也会比您已经拥有的要差。
与其保留完整的匹配索引集,不如保留第一个和最后一个。 这样一来,您就可以跳过搜索整个列表,并且在得分最高的情况下完全避免第二次通过。
void highScorer( player* array, int size )
{
int highScore = 0;
int firstHighI = -1, lastHighI = -1;
for ( int i = 0; i < size; i++ ) {
if ( array[i].pointsScored > highScore ) {
highScore = array[i].pointsScored;
firstHighI = i;
}
if ( array[i].pointsScored == highScore ) {
lastHighI = i;
}
}
if (firstHighI >= 0) {
std::cout << "\nThe highest scoring player(s) were:\n";
for ( int i = firstHighI; i < lastHighI; i++ ) {
if ( array[i].pointsScored == highScore ) {
std::cout << array[i].playerName << ", ";
}
}
std::cout << array[lastHighI].playerName << " with a score of " << highScore;
if ( highScore != 1 ) {
std::cout << " points!\n";
}
else {
std::cout << " point!\n";
}
}
std::cout << "\n";
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.