外排序简单实现

就是文件读写+败者树实现,交作业了

从特定命名格式的文件(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();


}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值