LINUX.ORG.RU

Написать сортировку файла за 3 часа (брутал-собес)

 , ,


2

4

Задача:
Написать сортировку файла.

Требования:
Дан текстовый файл размером 4 Гб. Файл содержит строки в кодировке UTF-8 средней длины 20 символов. Файл содержит три колонки, разделенные пробелами: «e-mail пользователя», «дата в формате ISO8601», «число, идентификатор некоторого объекта». Например,

superuser@yandex.ru 2010-12-02T13:30:12 11245
vasya@gmail.com 2011-03-25T00:00:02 88765
superuser@yandex.ru 2010-12-02T13:40:15 11244


У вас в распоряжении есть 512 Мб памяти.

Нужно написать программу, которая сортирует файл:
./sort input.txt output.txt

Прежде чем приступить к реализации, расскажите, пожалуйста, детали алгоритма, который вы будете реализовывать.

Если бы минут за 10, а за 3 часа, это же что-то очень крутое нужно, нет не справлюсь.

anonymous
()

Сортировка слиянием:

Промежуточные сортированные файлы (<=512М) + merge

anonymous
()

10 тысяч

Deleted
()
Ответ на: комментарий от anonymous

Зачем это надо, строки копировать. Сортировать надо индекс, а потом создать новый сортированный файл.

anonymous
()

Т.е. сортировать тупо как строки? Не по имени, серверу или дате?

1. «сжать»: имена повторяющиеся в список, собаку выкинуть, серверы закодировать IP или просто список в памяти держать, время в целое. Получится ок. 4 000 000 000/40=100млн. записей по 8байт. 2. блоками, через промежуточные файлы.

ziemin ★★
()

Если реализация и язык программирования не важен, то можно распечатать файл, нанять пучок разнорабочих которые сначала раскидают в стопки по буквам латинского алфавита, а потом рассортируют внутри стопок.

Думаю, три часа им хватит с лихвой. Детали алгоритма влезут в пару-тройку предложений.

shrub ★★★★★
()
Ответ на: комментарий от anonymous

И как сортировать такой индекс? куеву тучу reads делать с произвольным доступом по входному файлу?

nerdogeek
() автор топика

Про эффективность ничего не сказано: тогда тупо читаем n*log(n) раз файл в поисках очередной строки и пишем ее в выходной файл и ведем в памяти таблицу «использованных» строк из входного файла.

anonymous
()

Кстати, если дату перевести в unix timestamp,а id в int то датасет ужмётся в два раза.

Два чая мне за это.

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

по какому критерию надо сортировать-то?

Сорри, я хз. Это дословное описание задания. В принципе, как я понял, данные можно сортировать просто как строки.

nerdogeek
() автор топика

втупую:

1. Проходим весь файл, ищем минимальную строку. Пишем в выходной файл. Читаем исходный снова, ищем строку, бОльшую предыдущей, но меньшую остальных. Пишем. Смыть, повторить до тех пор, пока размеры файлов в строках не сравняются.

2. Играемся со свопом и флагами mmap-a, mmap-им файл, сортируем хоть qsort-ом. За 3 часа, вероятно, отсортирует.

arkhnchul ★★★
()
Ответ на: комментарий от anonymous

Сортировать надо индекс, а потом создать новый сортированный файл.

А анонимус прав. Вместе с индексом сохраняем смещение в файле чтобы быстро найти потом запись. Правда, это если нужна сортировка по индексу.

true_admin ★★★★★
()

Файл содержит строки в кодировке UTF-8 средней длины 20 символов

Вообще гонево какое-то. Только дата занимает 20 символов. И критерий сортировки не указан и необходимая эффективность алгоритма.

Сейчас на любой предложенный алгоритм ТС будет вводить доп. ограничения.

Давай все параметры сразу, а то начнешь юлить.

anonymous
()
Ответ на: комментарий от ziemin

Почему в два?

потому что ТС написал что длина строки 20символов в среднем, а индекс и timestamp занимают очень дофига... Ну да, из предложенных примеров этого не следует.

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

там 214млн записей, ты хоть представляешь кол-во проходов?

представляю. ТС о непосредственно требованиях ко времени исполнения алгоритма и недопустимости решений в лоб ничего не говорил.

arkhnchul ★★★
()
Ответ на: комментарий от true_admin

Если можно создавать промежуточные файлы, то mergesort решает

anonymous
()
Ответ на: комментарий от arkhnchul

3. Берем латинский алфавит/коды символов. Перебираем в цикле, проходами по файлу выбираем масивы строк с соответствующим началом, потом сортируем, пишем в выходной файл.

arkhnchul ★★★
()
Ответ на: комментарий от true_admin

Не, свое решение я потом кину по ссылке на гитхаб в тред.

nerdogeek
() автор топика
Ответ на: комментарий от ziemin

4. Берем латинский алфавит/коды символов. Проходим этот самый один раз по исходному файлу, пишем строки в кучку соответствующих файлов. Потом читаем сии файлы, сортируем, пишем в выходной.

arkhnchul ★★★
()
Ответ на: комментарий от true_admin

А анонимус прав. Вместе с индексом сохраняем смещение в файле чтобы быстро найти потом запись. Правда, это если нужна сортировка по индексу.

Только при ублюдочном критерии 20символов на строку в 4Гб файле и неизвестно можно ли создавать промежуточные файлы, 512Мб не хватит для ведения >200,000,000 индексов.

anonymous
()
Ответ на: комментарий от arkhnchul

Ну да. Для ускорения можно писать не по первым буквам, а по первым буквам и длине. Тогда слияние ещё быстрее будет

ziemin ★★
()
Ответ на: комментарий от ziemin

Естественно первые буквы в сам файл писать не надо.

ziemin ★★
()

спамер?
(база адрессов на 4 гига...)

invy ★★★★★
()
Последнее исправление: invy (всего исправлений: 1)
Ответ на: комментарий от anonymous

512Мб не хватит для ведения >200,000,000 индексов.

да, но можно разделить задачу на n кусков и выцеплять из файла только данные что попадают в нужный интервал.

true_admin ★★★★★
()

Нужно написать программу, которая сортирует файл:
Прежде чем приступить к реализации, расскажите, пожалуйста, детали алгоритма, который вы будете реализовывать.

В чём смысл сего действия? Это одноразовая операция? Зачем программу-то писать? Где 4-гиговый файл нужно скачать для проверки?

Вариант решения: Подключить дополнительный swap файл к имеющимся 512MB. Запустить

$ ./sort.sh input.txt output.txt
$ cat sort.sh 
#!/bin/sh
sort $1 > $2

justAmoment ★★★★★
()

сколько памяти на винче можно использовать?

грубо говоря:

1). разбиение на блоки <256Mb (информация об отступах в отдельный файл)

на выходе: файл с информацией об оступах

2). для каждого блока отступы сортировать через qsort потом в группироваь в отдельном блоке памяти и обратно в файл

на выходе: частично сортированный файл

3). мерже сортом объединять частично сортированные блоки по 2. тут в зависимости от ответа на 1 вопрос могут быть разные подходы.

P.S. жаль не выходной можно было бы поиграться.

qnikst ★★★★★
()

Я бы так сделал: время в time_t, id в short(?) int, имя @-сервера в словарь; наверное short-ключа хватит. При необходимости и имя юзера можно неплохо захаффманить. Дальше максимальными блоками quick-sort и во временный файл, по пути запоминая границы. Потом слиянием с каждой границы в результат (заодно распаковав).

anonymous
()
Ответ на: комментарий от true_admin

с учетом того, что это адреса почт и цифры, которые составляют самую нижнюю часть юникода-8, то >1-байтными случаями можно пренебречь.

cdshines ★★★★★
()
Ответ на: комментарий от beastie

да что уж там, сразу man sort, оно умеет выгружать промежуточные данные на диск.

true_admin ★★★★★
()
Ответ на: комментарий от anonymous

Слияние лучше наверное так:
1. первый раз читаем с каждой границы элемент в массив/список, сортируем, запоминая какой откуда пришел
2. пишем в результат первый элемент массива
3. из его границы получаем следующий (если есть) и вставляем в сортированную позицию
4. повторяем п.2.

arturpub ★★
()
Ответ на: комментарий от true_admin

во-первых N log N, т.к. сортировка по умолчанию это вызов quicksort. ну у тебя есть 3 часа, пока пишешь нормальное :)

P.S. дерево индексы и т.п. тут нафиг не нужно, для начала нужно поделить и выбрать правильную стратегию объединения, (на это и так эти 3 часа уйдут), а всякие «красивости» приделывать потом.

qnikst ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.