C++压缩两个for循环以提高效率



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

对于一个函数,我必须输出最高分数和相关的名称。如果有多个案例,我必须输出所有的名称。

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

我就是这样处理的:

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

我想把这个浓缩成一个循环。除非有人提出更有效的方法。我认为对数据进行排序是没有必要的。此外,如果已经排序,如何确定一步中是否有多个"高分"案例。

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

循环之后,你只需要打印带有该列表中索引的玩家,而不需要再次找出谁拥有高核心。

一种解决方案是在搜索高分时记录玩家的姓名。如果它等于当前的高分,则在"名称集合字符串"中附加一个额外的名称,如果它更高,则将名称留空,并记录新的高分和新名称。我会将名称的打印输出实现为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.

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

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

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

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

最新更新