就是文件读写+败者树实现,交作业了
从特定命名格式的文件(temp0.txt,temp1.txt ...,temp%d.txt)中读取数据然后在内存中排序,再输出到另一个文件
败者树初始化操作有部分代码与后面循坏排序的代码重复,但不能合并,必须先单独初始化。而且loser数组必须初始化为data数组中最小值的索引,然后再调用调整函数
循环排序的结束条件:排序得出的最小值所在文件已经访问到底(EOF)。当第x个文件访问完毕,在败者树中进行比较时,将视为一个很大的值,一直被压在loser[1-i]中,不可能作为最小值loser[0]输出,除非所有比较的值都是“最大值”
class loserTree {
int m_scr_count;
bool* m_is_fileEmpty;
int* data,*loser;
char* m_filename_format,*m_dst_name;
public:
loserTree(const char* scr, const char* dst, int cnt) {
m_scr_count = cnt;
m_filename_format = new char[strlen(scr) + 1];
strcpy_s(m_filename_format, strlen(scr) + 1, scr);
m_dst_name = new char[strlen(dst) + 1];
strcpy_s(m_dst_name, strlen(dst) + 1, dst);
data = loser = nullptr;
m_is_fileEmpty = nullptr;
}
~loserTree() {
if (m_filename_format) {
delete[] m_filename_format; m_filename_format = nullptr;
}
if (data) {
delete[] data; data = nullptr;
}
if (loser) {
delete[] loser; loser = nullptr;
}
if (m_filename_format) {
delete[] m_filename_format; m_filename_format = nullptr;
}
if (m_dst_name) {
delete[] m_dst_name; m_dst_name = nullptr;
}
}
void upData_adjust(int index) {//data[]的下标
int parent = (m_scr_count + index) / 2;//loser[]的下标
while (parent > 0) {//0不用比,1还要
if (!is_dataSmaller(index, loser[parent]))swap(index, loser[parent]);//数值大就交换下标,留在败者树上
parent /= 2;//往上走
}
loser[0] = index;//index始终指向最小值
}
bool is_dataSmaller(int a, int b) {
cout << a << ' ' << b << endl;
if (m_is_fileEmpty[a])return false;//没有数据不能比了,视为最大值,返回另一个
if (m_is_fileEmpty[b])return true;
if (data[a] < data[b])return true;
if (data[a] == data[b])return a < b;
else return false;
}
int read_File2MEM(FILE* path, int* a, int num) {//批量读入数据
int i = 0;
while (i < num && fscanf_s(path, "%d", &a[i]) != EOF)i++;//数据源之间有空格,但会自动过滤
return i;//实际读入数据的数量
}
void merge_sort() {
m_is_fileEmpty = new bool[m_scr_count] {0};
data = new int[m_scr_count];
loser = new int[m_scr_count];
FILE** fin_ary = new FILE * [m_scr_count], *fout;//记录文件流对象
char temp_filename[20];
int min = 9999, min_index = -1;
for (int i = 0; i < m_scr_count; i++) {//建立数据源的文件流
sprintf_s(temp_filename, 15, m_filename_format, i);
if (fopen_s(&fin_ary[i], temp_filename, "rt") == 0) {//打开了
//fprintf_s(fin_ary[i], "%d", data[i]);
fscanf_s(fin_ary[i], "%d", &data[i]);//顺便初始化data
if (min > data[i]) { min = data[i]; min_index = i; }
}
else {
m_is_fileEmpty[i] = 1;
cout << temp_filename << ", open failed" << endl;
}
}
fopen_s(&fout, m_dst_name, "wt");//建立文件流
if (min_index == -1) {
cout << "loserTree::merge_sort, empty files" << endl; goto END; }//empty files
//下面两个for初始化败者树
for (int i = 0; i < m_scr_count; i++)loser[i] = min_index;
for (int i = 0; i < m_scr_count; i++) {
upData_adjust(i);
}
//进行排序
while (1) {
fprintf_s(fout, "%d ", data[loser[0]]);//输出最小值
if (read_File2MEM(fin_ary[loser[0]], &data[loser[0]], 1) != 1) {//补充下一个
m_is_fileEmpty[loser[0]] = 1;//到文件尾了
}
upData_adjust(loser[0]);
if (m_is_fileEmpty[loser[0]] == 1)break;
}
END:
for (int i = 0; i < m_scr_count; i++) fclose(fin_ary[i]);
delete[] fin_ary; fin_ary = nullptr;
cout << "loserTree::merge_sort, end" << endl;
}
};
void test04() {
//设置了temp0.txt到temp4.txt共5个待排序合并的文件
loserTree lt("temp%d.txt", ".\\dst.txt", 5);
lt.merge_sort();
}