C ++ Condense两个for循环来提高效率

时间:2012-09-10 22:13:22

标签: c++ arrays

我有一个结构数组,我需要从中检索数据。该数组包含名称和分数。

对于一个功能,我必须输出最高分和相关名称。如果有多种情况,我必须输出所有名称。

我不能使用矢量或列表。 (否则我会)我只想在同一步骤中执行这两个动作。

这就是我处理它的方式:

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”案例。

6 个答案:

答案 0 :(得分:3)

除了highScore变量之外,您还可以创建第二个变量,例如std::list(或手动链接列表,甚至是小数组,具体取决于您允许使用的内容)。在此列表中,您可以跟踪实际拥有当前高分的人员的指数。如果找到新的高分,则清除该列表并添加具有新高分的人。如果发现有高分的人,你只需将他添加到列表中即可。

然后在循环之后,您只需要打印带有此列表中索引的玩家,而不是再次找出具有高分的人。

答案 1 :(得分:2)

一种解决方案是在搜索高分时记录玩家的名字。如果它等于当前的高分,则在“名称字符串集合”中附加一个名称,如果它更高,则删除名称,并记录新的高分和新名称。我将名称的打印输出实现为ostringstream,以确保您不会在缓冲区上运行。然后,当你完成后,打印出你的名字。

答案 2 :(得分:1)

在您通过第一个(仅)通过时,保留最高分的索引集。然后,当您完成后,您将拥有与该最高分相对应的索引集。在我刚刚编写的语言的伪代码中:

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.

如果您没有可用的动态列表,列表可以是与score数组大小相同的静态数组,以确保它总是足够大。

答案 3 :(得分:1)

现在你的第一个循环是跟踪高分。如果它还跟踪所有匹配的名称,您可以在循环结束时输出名称。你仍然需要第二个循环来浏览这些名称,这是无法避免的。

答案 4 :(得分:1)

以较低的存储成本,您可以在同一传球中计算高分和各自的球员:

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;
}

为了回答你原来的问题,我认为没有任何方法可以在一个循环中找到输出所有具有高分的玩家。即使对分数数组进行预先排序也会比您现有的更糟糕。

答案 5 :(得分:0)

我不会保留完整的匹配索引,而是保留第一个和最后一个。这可以让你跳过搜索整个列表,并在有唯一最高分的情况下完全避免第二遍。

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";
}