2012-09-10 61 views
0

我有一個結構數組,我需要從中檢索數據。該數組包含名稱和分數。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 

我想這凝結到一個for循環。除非有人建議採用更有效的方法。我認爲排序數據是沒有必要的。此外,如果它是分類的,那麼如何確定一步中是否存在多個「highScore」情況。

+5

在這種情況下進行兩次通過是典型的,它仍然是線性的。如果你真的希望你可以保留一個索引列表,然後在找到新的高分時清空它。 –

+0

Minor nitpicks:'return;'在'void'函數末尾是不必要的,並且一些評論過多(我正在看你,'//爲了可讀性增加新行)。 –

+0

哈哈!男人我完全同意你@Brendan Long,但它是作業,他們想要過度評論。不過,你是對的。 – frankV

回答

2

解決方法之一就是在搜索最高分時記錄玩家的姓名。如果它等於當前的高分,則將附加名稱附加到「名稱字符串集合」中,如果名稱更高,則將名稱空白,並記錄新的高分和新名稱。我將打印輸出名稱爲ostringstream,以確保您不會運行緩衝區。然後當你完成後,打印出你的名字。

+0

TA提出了這個建議,但表示使用了一個數組。我就像「你如何追加陣列?」但沒有說什麼。好主意只是保持一個字符串。我會看看它是否有效。謝謝! – frankV

+0

@frankV由於您知道列表的大小(參數中的'int size'),只要稍後刪除[]',您就可以使用'new int [size]'創建一個數組。它不如使用'vector'好,但它可能是他們期望的。 –

+0

我試過了。編譯器通過了一個紅旗。我發現獲取數組元素大小的唯一方法是'int sizeOfArray = sizeof(array)/ sizeof(* array)';'由於某種原因,您不能重複使用它來聲明另一個數組。 – frankV

3

除了您的highScore變量之外,您還創建了第二個變量,例如std::list(或手動鏈接列表或甚至是小數組,取決於您允許使用的內容)。在此列表中,您可以追蹤實際擁有當前高分的人員的指數。如果發現新的高分,則清除該列表並添加新的高分。如果有人被發現擁有高分,你只需將他添加到列表中即可。

然後循環後,您只需要打印列表中的索引玩家,而不是再次找出誰有高分。

+1

我敢打賭,如果'std :: vector'是禁止的,那麼'std :: list'也是。 –

+0

@larsmans:是的,我在你的評論前改變了我的回答。 – orlp

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. 

如果您還沒有一個動態的列表中可用做,這個名單可以是相同大小的分數排列的靜態數組,以確保它總是大足夠。

+0

這基本上是我描述的。 – orlp

+0

雖然不能使用列表。 – frankV

+0

@frankV:「列表」是一個抽象概念。您可以使用多種不同的數據結構來保存「列表」。例如,您可以爲此創建一個新數組(要求使用與原始列表相同的大小以確保所有內容都適合最差情況)。 –

1

現在你的第一個循環正在跟蹤高分。如果它還跟蹤所有匹配的名稱,則可以在循環完成時輸出名稱。你仍然需要第二個循環來通過這些名字,這是無法避免的。

+0

它需要較少的額外內存來存儲索引,而不是名稱本身。這也和我的回答相同:) – orlp

+0

@nightcracker:取決於「名稱」是一個「std :: string」還是一個「char const *」。 –

+0

@nightcracker,我認爲在我寫我的時候創建了大約4個新答案 - 我猜想晚了。你對這些指數是正確的。 –

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

要回答你原來的問題,我不認爲有任何方式任何的發現輸出所有得分高的球員,在一個循環。即使對樂譜數組進行預先排序也會比現有的更糟糕。