是的,无论如何,使用 qsort()。按照 SpiderPig 的建议,通过将整个文件读入内存来使用它,或者作为内存中的排序,用于运行适合内存的运行,为合并排序做准备。不要担心最坏情况下的性能。一个体面的实现将采用(第一、最后、中间)的中值来对已经排序和倒序的病理情况进行快速排序,并在随机情况下获得更好的平均性能。
这个全内存示例向您展示了如何使用 qsort:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct record_tag
{
int key;
char data[12];
} record_type, *record_ptr;
const record_type * record_cptr;
void create_file(const char *filename, int n)
{
record_type buf;
int i;
FILE *fptr = fopen(filename, "wb");
for (i=0; i<n; ++i)
{
buf.key = rand();
snprintf(buf.data, sizeof buf.data, "%d", buf.key);
fwrite(&buf, sizeof buf, 1, fptr);
}
fclose(fptr);
}
/* Key comparison function used by qsort(): */
int compare_records(const void *x, const void *y)
{
const record_ptr a=(const record_ptr)x;
const record_ptr b=(const record_ptr)y;
return (a->key > b->key) - (a->key < b->key);
}
/* Read an input file of (record_type) records, sort by key field, and write to the output file */
void sort_file(const char *ifname, const char *ofname)
{
const size_t MAXREC = 10000;
int n;
FILE *ifile, *ofile;
record_ptr buffer;
ifile = fopen(ifname, "rb");
buffer = (record_ptr) malloc(MAXREC*sizeof *buffer);
n = fread(buffer, sizeof *buffer, MAXREC, ifile);
fclose(ifile);
qsort(buffer, n, sizeof *buffer, compare_records);
ofile = fopen(ofname, "wb");
fwrite(buffer, sizeof *buffer, n, ofile);
fclose(ofile);
}
void show_file(const char *fname)
{
record_type buf;
int n = 0;
FILE *fptr = fopen(fname, "rb");
while (1 == fread(&buf, sizeof buf, 1, fptr))
{
printf("%9d : %-12s\n", buf.key, buf.data);
++n;
}
printf("%d records read", n);
}
int main(void)
{
srand(time(NULL));
create_file("test.dat", 99);
sort_file("test.dat", "test.out");
show_file("test.out");
return 0;
}
注意 compare_records 函数。qsort() 函数需要一个接受 void 指针的函数,因此必须将这些指针转换为正确的类型。然后是模式:
(left > right) - (left < right)
...如果左参数更大,则返回 1,如果它们相等,则返回 0,如果右参数更大,则返回 -1。
可以改进的。首先,绝对没有错误检查。这在生产代码中是不明智的。其次,您可以检查输入文件以获取文件大小,而不是猜测它小于某个 MAXxxx 值。一种方法是使用ftell。(按照链接获取文件大小示例。)然后,使用该值分配一个缓冲区,该缓冲区的大小足以对数据进行 qsort 排序。
如果没有足够的空间(如果 malloc 返回 NULL),那么您可以退回到对适合内存的块进行排序(使用 qsort,如代码片段中所示),将它们写入单独的临时文件,然后将它们合并为单个输出文件。这更复杂,而且很少这样做,因为有专门为对大文件进行排序而设计的排序/合并实用程序。