我有一个结构数组,需要从中检索数据。数组包含名称和分数。
对于一个函数,我必须输出最高分数和相关的名称。如果有多个案例,我必须输出所有的名称。
我不能使用矢量或列表。(否则我会)我只想在同一步骤中执行两个操作。
我就是这样处理的:
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";
}