外部排序C++版

     排序是编程中很常用的操作。当要排序的数据量很大,无法一次装入内存时,就要使用外部排序。
     外部排序通常的做法是先把数据分成多个可以一次装入内存的小段,对这些段分别使用内部排序,将排好序的段依次写入磁盘,再进行多路归并。
     多路归并通常用败者树来加速,但既然stl里有现成的priority_queue,我们可以偷个懒,不去重复发明轮子。
     废话少说,我们直接上程序。
 
     首先是数据生成器,不做其他什么操作,只是像data.dat中写入一些随机数,注意我们这里生成的全是正整数,运行这个程序一段时间以后我们按下ctrl+C。
 
 1 #include <fstream>
 2 #include <ctime>
 3 #include <cstdlib>
 4 using namespace std;
 5 
 6 int main()
 7 {
 8      ofstream os("data.dat");
 9      srand(time(NULL));
10      while(true)
11           os << rand() << endl;
12 }

 

 
接下来是我们的主要程序:
 
  1 #include <iostream>
  2 #include <fstream>
  3 #include <sstream>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <cstdio>
  7 #include <map>
  8 #include <vector>
  9 #include <queue>
 10 
 11 class ExternalSort
 12 {
 13      //分段排序并写入文件
 14      struct FilePart
 15      {
 16           int index;
 17           std::string file;
 18           std::ifstream in;
 19           int next;
 20           FilePart(int i) : index(i), file(""), in(), next(-2)
 21           {
 22                std::ostringstream os;
 23                os << ".temp." << index << ".dat";
 24                file = os.str();
 25           }
 26           void writeFile(int* array, int sz)
 27           {
 28                std::cout  << file << " created" << std::endl;
 29                std::ofstream of(file.c_str());
 30                for(int i = 0; i < sz; i++)
 31                     of << array[i] << std::endl;     
 32                in.open(file.c_str());
 33           }
 34 
 35           int peek()
 36           {
 37                if(next == -2)
 38                     getNext();
 39                return next;
 40           }          
 41 
 42           int getNext()
 43           {
 44                in >> next;
 45                if(!in)
 46                {
 47                     next = -1;
 48                     return next;
 49                }
 50                return next;
 51           }
 52           ~FilePart()
 53           {
 54                if(remove(file.c_str())== 0)//删除临时文件
 55                     std::cout << file << " deleted" << std::endl;
 56           }
 57      };
 58 
 59 //比较器,注意这里用的是大于,这样使得优先队列每次top都访问到拥有最小的next的FilePart
 60      struct Comparator 
 61      {
 62           bool operator()(FilePart* fp1, FilePart* fp2)
 63           {
 64                return fp1->peek() > fp2->peek();
 65           }
 66      };
 67      const static int READ_NUM = 10000000;//每次读取一千万个数
 68      std::ifstream input;
 69      int k;
 70      std::vector<FilePart*> forDelete;
 71 public:
 72      ExternalSort(const char* fn) : input(fn), forDelete() {}
 73 
 74      void sort()
 75      {
 76           split();
 77           merge();
 78      }
 79      //快速排序
 80      void quickSort(int* array, int a, int b)
 81      {
 82           if(a < b)
 83           {
 84                int mid = partition(array, a, b);
 85                quickSort(array, a, mid - 1);
 86                quickSort(array, mid + 1, b);
 87           }
 88      }
 89 
 90      ~ExternalSort()
 91      {
 92           for(std::vector<FilePart*>::iterator it = forDelete.begin(); it != forDelete.end(); ++it)
 93                if(*it)
 94                     delete *it;
 95      }
 96      
 97 private:
 98      int partition(int* array, int a, int b)
 99      {
100           int key = array[b];
101           int index = a;
102           for(int i = a; i < b; i++)
103                if(array[i] < key)
104                     std::swap(array[i], array[index++]);
105           std::swap(array[b], array[index]);
106           return index;
107      }
108 
109      void merge()
110      {
111           std::priority_queue<FilePart*, std::vector<FilePart*>, Comparator> pq(forDelete.begin(), forDelete.end());
112           std::ofstream os("output.dat");
113           while(pq.size())
114           {
115                FilePart* fp = pq.top();//取得拥有最小的next的FilePart
116                pq.pop();//从队列中删除它
117                int num = fp->peek();
118                os << num << std::endl;//写入输出文件
119                if(fp->getNext() != -1)//取得下一个值,由于我们的数据都是正整数,得到-1意味着已到达文件末尾
120                     pq.push(fp);//如果有下一个,就将它再次加入队列
121           }     
122      }
123      
124      void split()
125      {
126           k = 0;
127           while(input)
128           {
129                int* buf = new int[READ_NUM];
130                int i = 0;
131                for(; i < READ_NUM && input; i++)
132                     input >> buf[i];
133                if(!input)
134                     i--;
135                if(i == 0)
136                     continue;
137                quickSort(buf, 0, i - 1);//排序
138                FilePart* fp = new FilePart(k);
139                forDelete.push_back(fp);
140                fp->writeFile(buf, i);//写入临时文件
141                k++;
142                delete[] buf;
143           }     
144      }
145 };

 


 
main函数:
int main(int argc, char** argv)
{
     if(argc != 2)
     {
          cout << "Usage sort <file>" << endl;
          exit(1);
     }
     ExternalSort es(argv[1]);
     clock_t c1 = clock();
     es.sort();
     clock_t c2 = clock();
     float t = (c2 - c1) / CLOCKS_PER_SEC;
     cout << "Sort done in " << t << " seconds." << endl;
}

 

 
测试电脑比较烂,2.6G的测试数据花了了1378秒才跑完

转载于:https://www.cnblogs.com/Psyche/archive/2012/07/18/cpp_external_sorting.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
外部排序是一种常见的排序方法,它能够处理无法一次性装入内存的大规模数据。下面是一个简单的外部排序的C代码示例: ```c #include <stdio.h> #include <stdlib.h> #define MAX_LINE_LENGTH 256 void merge_sort(char **input_files, int num_files, char *output_file) { FILE **input_fp = malloc(num_files * sizeof(FILE *)); FILE *output_fp = fopen(output_file, "w"); char **lines = malloc(num_files * sizeof(char *)); int *indices = malloc(num_files * sizeof(int)); int i; // Open input files for (i = 0; i < num_files; i++) { input_fp[i] = fopen(input_files[i], "r"); if (!input_fp[i]) { perror("Failed to open input file"); exit(1); } // Allocate memory for lines lines[i] = malloc(MAX_LINE_LENGTH); if (!lines[i]) { perror("Failed to allocate memory for line"); exit(1); } // Read first line if (fgets(lines[i], MAX_LINE_LENGTH, input_fp[i])) { indices[i] = i; } else { indices[i] = -1; } } while (1) { // Find smallest line int min_index = -1; for (i = 0; i < num_files; i++) { if (indices[i] == -1) { continue; } if (min_index == -1 || strcmp(lines[i], lines[min_index]) < 0) { min_index = i; } } if (min_index == -1) { break; } // Write smallest line to output file fputs(lines[min_index], output_fp); // Read next line from file if (fgets(lines[min_index], MAX_LINE_LENGTH, input_fp[min_index])) { indices[min_index] = min_index; } else { indices[min_index] = -1; } } // Close files and free memory for (i = 0; i < num_files; i++) { fclose(input_fp[i]); free(lines[i]); } free(input_fp); free(lines); free(indices); fclose(output_fp); } void external_sort(char *input_file, char *output_file, int max_lines) { FILE *input_fp = fopen(input_file, "r"); char **lines = malloc(max_lines * sizeof(char *)); int i, j; if (!input_fp) { perror("Failed to open input file"); exit(1); } // Allocate memory for lines for (i = 0; i < max_lines; i++) { lines[i] = malloc(MAX_LINE_LENGTH); if (!lines[i]) { perror("Failed to allocate memory for line"); exit(1); } } // Split input file into smaller files i = 0; while (!feof(input_fp)) { // Read lines for (j = 0; j < max_lines && !feof(input_fp); j++) { fgets(lines[j], MAX_LINE_LENGTH, input_fp); } // Sort lines and write to file qsort(lines, j, sizeof(char *), strcmp); char filename[MAX_LINE_LENGTH]; sprintf(filename, "temp_%d", i++); FILE *temp_fp = fopen(filename, "w"); if (!temp_fp) { perror("Failed to create temporary file"); exit(1); } for (int k = 0; k < j; k++) { fputs(lines[k], temp_fp); } fclose(temp_fp); } // Merge smaller files char **input_files = malloc(i * sizeof(char *)); for (j = 0; j < i; j++) { input_files[j] = malloc(MAX_LINE_LENGTH); sprintf(input_files[j], "temp_%d", j); } merge_sort(input_files, i, output_file); // Delete temporary files for (j = 0; j < i; j++) { remove(input_files[j]); free(input_files[j]); } free(input_files); for (i = 0; i < max_lines; i++) { free(lines[i]); } free(lines); fclose(input_fp); } int main(int argc, char *argv[]) { if (argc != 4) { fprintf(stderr, "Usage: %s input_file output_file max_lines\n", argv[0]); exit(1); } char *input_file = argv[1]; char *output_file = argv[2]; int max_lines = atoi(argv[3]); external_sort(input_file, output_file, max_lines); return 0; } ``` 这段代码分为两个部分:`external_sort`函数和`merge_sort`函数。`external_sort`函数将输入文件分割成多个小文件,对每个小文件进行内部排序,然后将它们合并为一个输出文件,这里使用了`merge_sort`函数。`merge_sort`函数负责将多个输入文件合并为一个输出文件,基本思路是将每个文件的第一行读入内存,然后找出最小行并写入输出文件,接着将该文件的下一行读入内存,直到所有文件的行都已经处理完毕。 注意,这段代码仅供参考,实际应用中还需要考虑更多的细节问题,例如内存分配、文件打开与关闭、错误处理等等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值