Advertisement
jusohatam

Untitled

Dec 13th, 2021
709
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.33 KB | None | 0 0
  1. #include <iostream>
  2. #include <fstream>
  3. #include <sstream>
  4. #include <ctime>
  5. #include <tuple>
  6. #include <windows.h>
  7. #include <algorithm>
  8.  
  9. using namespace std;
  10.  
  11. unsigned long long half_free_ram() {
  12.     MEMORYSTATUSEX status;
  13.     status.dwLength = sizeof(status);
  14.     GlobalMemoryStatusEx(&status);
  15.     return status.ullAvailPhys / 2;
  16. }
  17.  
  18. class NaturalMerge {
  19. private:
  20.     // Счетчик количества сравнений
  21.     int count_compare = 0;
  22.  
  23.     // Счетчик количества перемещений
  24.     int count_move = 0;
  25.  
  26.     size_t chunk_size, segments = 0;
  27.     string filename;
  28.  
  29. public:
  30.     NaturalMerge(string& input_filename) {
  31.         size_t free_memory_size = half_free_ram();
  32.         chunk_size = free_memory_size / sizeof(string);
  33.         filename = input_filename;
  34.     }
  35.  
  36.     void write(ofstream &file, string &val, bool &flag) {
  37.         if (!val.empty()) {
  38.             if (flag) {
  39.                 file << "\n";
  40.             }
  41.             file << val;
  42.             ++count_move;
  43.             flag = true;
  44.         }
  45.     }
  46.  
  47.     bool compare(string& x, string& y) {
  48.         stringstream xs(x), ys(y);
  49.         string comp_x, comp_y;
  50.         xs >> comp_x;
  51.         ys >> comp_y;
  52.         ++count_compare;
  53.         return comp_x <= comp_y;
  54.     }
  55.  
  56.     void buff_merge(string * buff, size_t first, size_t middle, size_t last) {
  57.         size_t i = 0, j = 0;
  58.         string * tmp = new string[last-first];
  59.  
  60.         // Процедура слияния двух частей массива
  61.         while ((first+i < middle) && (middle+j < last)) {
  62.             // Если элемент из первой части больще, то запоминаем его
  63.             if (compare(buff[first+i],buff[middle+j])) {
  64.                 tmp[i+j] = buff[first+i];
  65.                 ++count_move;
  66.                 ++i;
  67.                 // Иначе запоминаем элемент из второй части массива
  68.             } else {
  69.                 tmp[i+j] = buff[middle+j];
  70.                 ++count_move;
  71.                 ++j;
  72.             }
  73.             ++count_compare;
  74.         }
  75.  
  76.         // Записываем оставшиеся элементы
  77.         while (first+i < middle) {
  78.             tmp[i+j] = buff[first+i];
  79.             ++count_move;
  80.             ++i;
  81.         }
  82.  
  83.         // Записываем оставшиеся элементы
  84.         while (middle+j < last) {
  85.             tmp[i+j] = buff[middle+j];
  86.             ++count_move;
  87.             ++j;
  88.         }
  89.  
  90.         // Перезаписываем отсортированные части в изначальный массив
  91.         for (int k = 0; k < i+j; ++k) {
  92.             buff[first+k] = tmp[k];
  93.             ++count_move;
  94.         }
  95.  
  96.         delete[] tmp;
  97.     }
  98.  
  99.     void buff_sort(string * buff, size_t first, size_t last) {
  100.         if (first + 1 >= last) {
  101.             return;
  102.         }
  103.         size_t middle = (first + last) / 2;
  104.         buff_sort(buff, first, middle);
  105.         buff_sort(buff, middle, last);
  106.         buff_merge(buff, first, middle, last);
  107.     }
  108.  
  109.     void write_buff(ofstream& file, string* buff, size_t& sz, bool& flag) {
  110.         for (size_t i = 0; i < sz; ++i) {
  111.             write(file, buff[i], flag);
  112.             ++count_move;
  113.         }
  114.     }
  115.  
  116.     void write_when_merge(ifstream& file_in, ofstream& file_out, string& val, bool& flag, bool& end) {
  117.         write(file_out, val, flag);
  118.         if (!file_in.eof()) {
  119.             getline(file_in, val);
  120.         } else {
  121.             end = true;
  122.         }
  123.     }
  124.  
  125.     void sort_and_write(ofstream& file_b, ofstream& file_c, string* buff, size_t& sz, bool& new_line_b, bool& new_line_c,
  126.                         bool& processed, bool& write_b, string& last_element_b, string& last_element_c) {
  127.  
  128.         // Сортируем полученный буффер внутренней сортировкой
  129.         buff_sort(buff, 0, sz);
  130.  
  131.         // Елси текущая серия является продолжением предыдущей серии в файле b, то записываем новую серию в файл b
  132.         if (compare(last_element_b, buff[0])) {
  133.             ++count_compare;
  134.             last_element_b = buff[sz-1];
  135.             write_buff(file_b, buff, sz, new_line_b);
  136.             write_b = false;
  137.         // Елси текущая серия является продолжением предыдущей серии в файле c, то записываем новую серию в файл c
  138.         } else if (compare(last_element_c, buff[0])) {
  139.             ++count_compare;
  140.             last_element_c = buff[sz-1];
  141.             write_buff(file_c, buff, sz, new_line_c);
  142.             write_b = true;
  143.         // Иначе записываем серию в порядке текущей очереди
  144.         } else if (write_b) {
  145.             write_b = !write_b;
  146.             write_buff(file_b, buff, sz, new_line_b);
  147.         } else {
  148.             write_b = !write_b;
  149.             write_buff(file_c, buff, sz, new_line_c);
  150.         }
  151.         processed = false;
  152.     }
  153.  
  154.     void separate() {
  155.         // Открываем файл a для чтения
  156.         ifstream file_a(filename, ios::out | ios::binary);
  157.         // Открываем файлы b, c для записи
  158.         ofstream file_b("b.bin", ios::in | ios::trunc | ios::binary),
  159.                 file_c("c.bin", ios::in | ios::trunc | ios::binary);
  160.         string x, last_element_b, last_element_c;
  161.         bool processed, write_b = true, new_line_b = false, new_line_c = false;
  162.         size_t tmp_count = 0;
  163.  
  164.         // Создаем буффер под данные
  165.         string * buff = new string[chunk_size];
  166.  
  167.         // Пока не кончился файл a
  168.         while (!file_a.eof()) {
  169.             getline(file_a, x);
  170.             buff[tmp_count++] = x;
  171.             processed = true;
  172.             // Если считали серию установленной длины, то выгружаем ее в файл b или c
  173.             if (tmp_count == chunk_size) {
  174.                 sort_and_write(file_b, file_c, buff, tmp_count, new_line_b, new_line_c, processed, write_b, last_element_b,
  175.                                last_element_c);
  176.                 tmp_count = 0;
  177.             }
  178.         }
  179.         // Если остались какие-то элементы меньше текущей серии, то также выгружаем их в файл b или c
  180.         if (processed) {
  181.             sort_and_write(file_b, file_c, buff, tmp_count, new_line_b, new_line_c, processed, write_b, last_element_b,
  182.                            last_element_c);
  183.         }
  184.  
  185.         // Удаляем буффер
  186.         delete[] buff;
  187.  
  188.         // Если файл c оказался пустым после разделения, то значит в файле b лежит отсортированная единая серия
  189.         if (last_element_c.empty()) {
  190.             segments = 1;
  191.         }
  192.  
  193.         // Закрываем файлы
  194.         file_a.close();
  195.         file_b.close();
  196.         file_c.close();
  197.     }
  198.  
  199.     void merge() {
  200.         // Открываем файл a для записи
  201.         ofstream file_a(filename, ios::in | ios::trunc | ios::binary);
  202.         // Открываем файлы b, c для чтения
  203.         ifstream file_b("b.bin", ios::out | ios::binary), file_c("c.bin", ios::out | ios::binary);
  204.         string x, y;
  205.         bool new_line_a = false, end_b = true, end_c = true;
  206.         // Читаем первую переменную из файла b
  207.         if (!file_b.eof()) {
  208.             getline(file_b, x);
  209.             end_b = false;
  210.         }
  211.         // Читаем первую переменную из файла c
  212.         if (!file_c.eof()) {
  213.             getline(file_c, y);
  214.             end_c = false;
  215.         }
  216.         // Пока не достигли конца файла b и c
  217.         while (!end_b && !end_c) {
  218.             // Если элемент из файла b меньше, чем из файла c, то сливаем из файла b
  219.             if (compare(x, y)) {
  220.                 write_when_merge(file_b, file_a, x, new_line_a, end_b);
  221.             // Иначе из файла c
  222.             } else {
  223.                 write_when_merge(file_c, file_a, y, new_line_a, end_c);
  224.             }
  225.             ++count_compare;
  226.         }
  227.  
  228.         // Сливаем оставшиеся данные из файлов b, c
  229.         while (!end_b) {
  230.             write_when_merge(file_b, file_a, x, new_line_a, end_b);
  231.         }
  232.         while (!end_c) {
  233.             write_when_merge(file_c, file_a, y, new_line_a, end_c);
  234.         }
  235.  
  236.         // Закрываем файлы
  237.         file_a.close();
  238.         file_b.close();
  239.         file_c.close();
  240.     }
  241.  
  242.     tuple<int, int, double> sort() {
  243.         // Время начала работы алгоритма
  244.         time_t time_begin = clock();
  245.  
  246.         // Функция сортировки
  247.         while (true) {
  248.             if (segments == 1) {
  249.                 break;
  250.             }
  251.             separate();
  252.             merge();
  253.         }
  254.         // Время окончания работы алгоритма
  255.         time_t time_end = clock();
  256.  
  257.         // Итоговое время работы алгоритма
  258.         double time_spent = (double)(time_end - time_begin) / (double)CLOCKS_PER_SEC;
  259.  
  260.         return {count_compare, count_move, time_spent};
  261.     }
  262.  
  263. };
  264.  
  265. void run_tests(size_t& n, string& filename) {
  266.     NaturalMerge dm(filename);
  267.     // Запуск функции сортировки
  268.     tuple<int, int, double> res = dm.sort();
  269.  
  270.     // Вывод полученных результатов прогона
  271.     cout << "N = " << n << "\n";
  272.     cout << "----------\n";
  273.     cout << "Count of compares: " << get<0>(res);
  274.     cout << "\nCount of moves: " << get<1>(res);
  275.     cout << "\nTime spent in sc: " << get<2>(res) << "\n\n";
  276. }
  277.  
  278. int main() {
  279.     size_t n1 = 100, n2 = 1000, n3 = 10000, n4 = 100000, n5 = 1000000;
  280.     string f1 = "a_n1.bin", f2 = "a_n2.bin", f3 = "a_n3.bin", f4 = "a_n4.bin", f5 = "a_n5.bin";
  281.  
  282.     run_tests(n1, f1);
  283.     run_tests(n2, f2);
  284.     run_tests(n3, f3);
  285.     run_tests(n4, f4);
  286.     run_tests(n5, f5);
  287. }
  288.  
  289. //N = 100
  290. //----------
  291. //Count of compares: 1104
  292. //Count of moves: 1644
  293. //Time spent in sc: 1.965
  294. //
  295. //N = 1000
  296. //----------
  297. //Count of compares: 17460
  298. //Count of moves: 22952
  299. //Time spent in sc: 1.975
  300. //
  301. //N = 10000
  302. //----------
  303. //Count of compares: 240804
  304. //Count of moves: 297232
  305. //Time spent in sc: 2.001
  306. //
  307. //N = 100000
  308. //----------
  309. //Count of compares: 3068002
  310. //Count of moves: 3637856
  311. //Time spent in sc: 4.207
  312. //
  313. //N = 1000000
  314. //----------
  315. //Count of compares: 37280304
  316. //Count of moves: 42902848
  317. //Time spent in sc: 24.544
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement