За 4 часа написать программу, которая отсортирует числа формата double
хранящихся в текстовом файле размером 1Гб (одно число в одной строке).
Пример
8.33891e+307
1.26192e+308
8.19572e+307
...
0
1.64584e+304
Программа должна использовать не более 100Мб оперативной памяти, и
работать не дольше 25-30 минут (на 2Гц современном процессоре).
Обязательные параметры: <имя файла не отсортированного> <имя файла отсортированного> Также должен быть написан генератор не
отсортированного 1Гб файла с числами формата double
Алгоритм — блочная сортировка
В аттаче пример готового приложения пока только бинари.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, digger51, Вы писали:
D>>В аттаче пример готового приложения пока только бинари. К>Смешно. Этюд в том, чтобы телепатически выкачать этот аттач?
К>
К>Ограничение на ОЗУ есть, а на дисковую память?
Здравствуйте, Кодт, Вы писали:
К>Смешно. Этюд в том, чтобы телепатически выкачать этот аттач?
Сорри вон он здесь
К>Ограничение на ОЗУ есть, а на дисковую память?
Нет
Здравствуйте, digger51, Вы писали:
К>>Ограничение на ОЗУ есть, а на дисковую память? D>Нет
Тогда заводим мега-своп-файл
1. Читаем из исходного файла по 100 мегабайт double'в или сколько влезет в память, сортируем эти пачки в памяти (квиксорт), сохраняем в файлы.
Всего получается порядка 10-20 файлов.
2. Открываем все эти 10-20 файлов и выполняем сортировку слиянием, результат записываем в результирующий файл.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, digger51, Вы писали:
К>>>Ограничение на ОЗУ есть, а на дисковую память? D>>Нет
К>Тогда заводим мега-своп-файл
К>1. Читаем из исходного файла по 100 мегабайт double'в или сколько влезет в память, сортируем эти пачки в памяти (квиксорт), сохраняем в файлы. К>Всего получается порядка 10-20 файлов.
К>2. Открываем все эти 10-20 файлов и выполняем сортировку слиянием, результат записываем в результирующий файл.
К>ВСЁ!
Наверное автор хочет чтобы написали пример
Причем мне кажется что при сортировке слиянием используя мега своп файл начнется тормозня.
Здравствуйте, codelord, Вы писали:
К>>1. Читаем из исходного файла по 100 мегабайт double'в или сколько влезет в память, сортируем эти пачки в памяти (квиксорт), сохраняем в файлы. К>>Всего получается порядка 10-20 файлов.
К>>2. Открываем все эти 10-20 файлов и выполняем сортировку слиянием, результат записываем в результирующий файл.
Да так я и сделал.
C>Наверное автор хочет чтобы написали пример C>Причем мне кажется что при сортировке слиянием используя мега своп файл начнется тормозня.
Именно. Хочется пример того как написали бы другие программисты.
Уже есть свой код и хочется сравнить с тем что напишут другие за 4 часа.
Тормозни особой нет, ведь памяти есть 100Мб можно кешировать.
Здравствуйте, codelord, Вы писали:
К>>Тогда заводим мега-своп-файл C>Причем мне кажется что при сортировке слиянием используя мега своп файл начнется тормозня.
Это была шютка. Мега-своп-файла не требуется.
C>Наверное автор хочет чтобы написали пример
Ну, я думаю, четыре часа уже прошли, конкурс можно считать размороженным
Вот примерно такой эскиз. Компилировать даже не пробовал.
// генератор имён временных файлов
string make_up_temp_filename(int);
// будем считать, что оба файла - вход и выход - уже открыты
ifstream srcfile;
ofstream dstfile;
vector< shared_ptr<fstream> > tempfiles; // временные файлы - будем создавать по ходу дела
////////////////////////////
// читаем-сортируем-пишем...
vector<double> block; // для сортировки в памяти
block.reserve(100000000 / sizeof(double)); // ну или сколько там памяти доступноwhile(srcfile)
{
block.resize(0);
// читаемwhile(block.size() < block.capacity() && srcfile)
{
double x; srcfile >> x;
if(srcfile.failbit())
break;
block.push_back(x);
}
if(block.size()==0)
break;
// сортируем
sort(block.begin(), block.end());
// записываем
shared_ptr<fstream> tempfile (new fstream(make_up_temp_filename(tempfiles.size()), ios_base::in|ios_base::out|ios_base::binary));
tempfile->write((const char*)&block[0], block.size()*sizeof(double));
tempfiles.push_back(tempfile);
}
////////////////////////
// выполняем слияние
vector<double> inputs (tempfiles.size());
// заполняем первый рядfor(int i=0, n=tempfiles.size(); i!=n; ++i)
tempfiles[i]->read((char*)&inputs[i], sizeof(double));
while(inputs.size() != 0)
{
int best = distance(inputs.begin(), min_element(inputs.begin(), inputs.end()));
dstfile << inputs[best] << endl;
// читаем новое значение из файла номер bestif(!*tempfiles[best])
{
inputs.erase(inputs.begin()+best);
tempfiles.erase(tempfiles.begin()+best);
}
else
{
tempfiles[best]->read((char*)&inputs[i], sizeof(double));
}
}
А>функция с таким назначением уже есть в стандарте, изобретение велосипеда, однако
Есть очень похожие функции — tmpnam (а в VC CRT — ещё и _tempnam). Никто не мешает определить make_up_temp_filename через них. Или сделать свою.
А>
А>shared_ptr<fstream> tempfile (new fstream(make_up_temp_filename(tempfiles.size()), ios_base::in|ios_base::out|ios_base::binary));
А>
А>не догоняю, зачем использовать shared_ptr
Затем, чтобы поместить fstream в вектор.
Поскольку поток не является типом-значением, непосредственно с ним такой фокус — vector<fstream> — не пройдёт.
Можно, конечно, повыкручиваться и сделать отложенную инициализацию пула потоков
А> int best = distance(inputs.begin(), min_element(inputs.begin(), inputs.end()));
А>
А>а что, std::max_element тут нельзя применить?
А при чём тут max_element?
Я выбираю из inputs наименьший элемент и получаю его индекс с помощью distance.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Перекуём баги на фичи!
Re[8]: Тестовое задание C++
От:
Аноним
Дата:
16.09.08 12:30
Оценка:
Здравствуйте, Кодт, Вы писали:
К>Есть очень похожие функции — tmpnam (а в VC CRT — ещё и _tempnam). Никто не мешает определить make_up_temp_filename через них. Или сделать свою.
ИМХО это затрудняет понимание и все такое.... Нарушение принципа Оккама... Можно вообще сделать что-то вроде:
#define BEGIN { #define END }
И дальше писать вместо скобок BEGIN и END, и это будет работать — только нафига?
А>>
А>>shared_ptr<fstream> tempfile (new fstream(make_up_temp_filename(tempfiles.size()), ios_base::in|ios_base::out|ios_base::binary));
А>>
А>>не догоняю, зачем использовать shared_ptr
К>Затем, чтобы поместить fstream в вектор.
Я в принципе догнал уж и сам... Правда объяснение дал бы другое — чтобы корректно закрыть все файлы при любом (вт.ч. аварийном) завершении кода. Потому как, ИМХО, никто не мешает хранить в векторе указатели на fstream — разве нет? Но это усложняет cleanup ( a propos — в коде не хватает, ИМХО, уничтожения созданных на диске временных файлов.... Если только ты не используешь стандартные функции, не только генерирующие имя, но и создающие временный файл, гарантированно уничтожающийся при окончании работы — в Unix такие вещи есть, в Win — не уверен, но вроде тоже)
К>А при чём тут max_element? К>Я выбираю из inputs наименьший элемент и получаю его индекс с помощью distance.
Хорошо, используем min_element
Re[8]: Тестовое задание C++
От:
Аноним
Дата:
16.09.08 12:36
Оценка:
P.S. Не воспринимай, плиз, разбор твоего кода как наезд на тебя лично. Если человек даже действительно нашел в твоем коде какие-то огрехи — это не значит, что ты дурак, и не значит, что он умный. ИМХО, чужие ошибки находить — ума много не требутся
Здравствуйте, <Аноним>, Вы писали:
К>>Есть очень похожие функции — tmpnam (а в VC CRT — ещё и _tempnam). Никто не мешает определить make_up_temp_filename через них. Или сделать свою. А>ИМХО это затрудняет понимание и все такое.... Нарушение принципа Оккама...
Это не нарушение принципа Оккама, а введение точки абстрагирования.
Кроме того, сишная функция работает с сишными же строками, а это всегда несколько стрёмно. Что там с потокобезопасностью, например? Опять же, для защиты от переполнения буфера MS рекомендует использовать другую функцию — tmpnam_s. Вот тут и пригодится абстрагирование.
А>>>не догоняю, зачем использовать shared_ptr К>>Затем, чтобы поместить fstream в вектор. А>Я в принципе догнал уж и сам... Правда объяснение дал бы другое — чтобы корректно закрыть все файлы при любом (вт.ч. аварийном) завершении кода. Потому как, ИМХО, никто не мешает хранить в векторе указатели на fstream — разве нет? Но это усложняет cleanup ( a propos — в коде не хватает, ИМХО, уничтожения созданных на диске временных файлов.... Если только ты не используешь стандартные функции, не только генерирующие имя, но и создающие временный файл, гарантированно уничтожающийся при окончании работы — в Unix такие вещи есть, в Win — не уверен, но вроде тоже)
Если мы сделаем локальный массив fstream'ов — то у его элементов тоже вызовутся деструкторы и позакрывают файлы.
А вот про удаление файлов — замечание верное! Это я забыл.