Rick York
Если бы я был на вашем месте, я бы сделал небольшой набор функций для работы с вашей структурой данных. Это очень сильно очистит код! Я думаю, что вы сможете увидеть логические ошибки гораздо проще. Вот несколько примеров :
int ReadRecord( details * pd, FILE * pf )
{
char a[512] = { 0 };
int i = 0;
while( ( i < 4 ) && fgets( a, sizeof a, pf ) )
{
if( ( a[0] == '\r' ) || ( a[0] == '\n' ) )
continue; // skip empty lines
switch( i )
{
case 0 :
strcpy( pd->title, a );
break;
case 1 :
strcpy( pd->platform, a );
break;
case 2 :
strcpy( pd->score, a );
break;
case 3 :
strcpy( pd->release_year, a );
break;
}
++i;
}
return i;
}
void CopyRecord( details *pddest, details *pdsource )
{
strcpy( pddest->title, pdsource->title );
strcpy( pddest->platform, pdsource->platform );
strcpy( pddest->score, pdsource->score );
strcpy( pddest->release_year, pdsource->release_year );
}
void SwapRecords( details *pda, details *pdb )
{
details temp = { 0 };
CopyRecord( temp, pda );
CopyRecord( pda, pdb );
CopyRecord( pdb, temp );
}
int main()
{
int j = 0;
FILE * newFile = fopen( "ign_new.txt", "w" );
FILE * myfile = fopen( "ign.txt", "r" );
if( myfile == NULL )
{
perror (" empty file ");
return -1;
}
// read the file
while( ReadRecord( &records[j], myfile ) )
{
++j;
}
fclose( myfile );
myfile = NULL;
printf( "read %d records\n", j );
// sort the records
int flag;
int n = j;
for( i = 1; i < n; i++ )
{
flag = 0;
for( j = 0; j < n - i; j++ )
{
if( atoi( record[j].score ) < atoi( record[j+1].score ) )
{
SwapRecords( &record[j], &record[j+1] );
flag = 1;
}
}
if( flag == 0 )
break;
}
// probably should do something with the records here
// like write them to the new file.g
fclose( newFile );
return 0;
}
Я бы посоветовал создать функцию WriteRecord, которая работает в обратном направлении от ReadRecord, чтобы они могли обрабатывать ввод/вывод друг друга. Не забудьте написать пустую строку в WriteRecord. ;)
Кстати, я еще не оценил вашу логику. Я оставил это на ваше усмотрение. Моя цель состояла в том, чтобы создать функции для последовательностей логики, которые имеют дело со структурой данных. Это может упростить логику обработки, и тогда вы сможете увидеть ее внутреннюю работу гораздо яснее.
Один намек - Я думаю, что термины циклов for, используемых при сортировке, неверны.
Какого черта. Вот как бы я это сделал. Часто при сортировке используется функция сравнения сравниваемых данных. Вот один из них для этой структуры данных :
int CompareRecords( details *pda, details * pdb )
{
// return true if record a's score is less than record b's
return atoi( pda->score ) < atoi( pdb->score );
}
Теперь вы можете написать такую функцию сортировки :
void SortRecords( details * pd, int count )
{
int i, j;
for( j = 0; j < count - 1; ++j )
{
// The highest score record floats to the top so we don't have to check
// the top any more -> start from the one after the outer loop index.
for( i = j + 1; i < count; ++i )
{
if( CompareRecords( &pd[j], &pd[i] ) )
SwapRecords( &pd[j], &pd[i] );
}
}
}
Обратите внимание - я вообще не пробовал этот код. Вы можете либо попробовать его и отладить, либо использовать то, что вы хотите от него.
Rick York
Я только что заметил, что вы написали, что у вас есть 18000 записей в файле. Фу! Чтобы помочь сортировке, я бы внес следующие изменения.
struct details
{
char title[256];
char platform [256];
char score[256];
char release_year[256];
int intscore;
};
void CopyRecord( details *pddest, details *pdsource )
{
memcpy( pddest, pdsource, sizeof( details ) );
}
int CompareRecords( details *pda, details * pdb )
{
// return true if record a's score is less than record b's
return pda->intscore < pdb->intscore;
}
// change ReadRecord to have this in case 2 :
case 2 :
strcpy( pd->score, a );
pd->intscore = atoi( a );
break;
Функции подкачки и сортировки не нуждаются в изменении. Это действительно ускорит сортировку, потому что ему не придется преобразовывать счет из строки в целое число так много раз при сравнении - он может напрямую сравнивать два целочисленных значения.