Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Слияние множества однородных текстовых файлов 
:(
    Опции темы
Merovingean
Дата 8.7.2015, 21:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.7.2015

Репутация: нет
Всего: нет



Добрый вечер.

Столкнулся с проблемой. Вроде и знаю как решить, но не слишком красиво получается.

Вопрос такой: Дано N файлов общим размером более 100 мегабайт. В файлах находятся отсортированные номера. Например, семи- или восьмизначные. Номера разделены между собой пробелами.
Нужно слить все файлы в один. Внутри файла-результата номера тоже должны быть отсортированы. При этом, нежелательно использовать оперативной памяти более 20-30 мегабайт.

Подскажите пожалуйста, как это покрасивее реализовать? Сам я пока не придумал ничего лучше, чем брать по одному из каждого файла, искать наименьший и совать его в выходной или сливать вместе попарно. Ну и вариации этих подходов.
PM MAIL   Вверх
feodorv
Дата 8.7.2015, 22:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Merovingean @  8.7.2015,  21:55 Найти цитируемый пост)
Сам я пока не придумал ничего лучше, чем брать по одному из каждого файла

А что здесь некрасивого?


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Merovingean
Дата 8.7.2015, 22:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.7.2015

Репутация: нет
Всего: нет



Цитата(feodorv @ 8.7.2015,  22:39)
А что здесь некрасивого?

Возможно, паранойя. Опыта мало.smile

Тогда уточню.
Ну вот скажем файлов оказалось 500 или 2000 или больше.
Предполагается, что открываются все файлы сразу и из каждого файла берется первый номер, в полученном массиве ищется меньший и кладется в выходной. Место найденного меньшего занимает следующий номер из того же файла, что и найденный меньший. Это хороший вариант? В плане производительности.

Это сообщение отредактировал(а) Merovingean - 8.7.2015, 22:50
PM MAIL   Вверх
xvr
Дата 9.7.2015, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(Merovingean @  8.7.2015,  21:55 Найти цитируемый пост)
Сам я пока не придумал ничего лучше, чем брать по одному из каждого файла, искать наименьший и совать его в выходной или сливать вместе попарно.

Это называется '[внешняя] сортировка слиянием'. Вполне стандартный метод. Подробности ищите в Гугле  smile 

PM MAIL   Вверх
feodorv
Дата 9.7.2015, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Merovingean @  8.7.2015,  22:49 Найти цитируемый пост)
Предполагается, что открываются все файлы сразу и из каждого файла берется первый номер, в полученном массиве ищется меньший и кладется в выходной. Место найденного меньшего занимает следующий номер из того же файла, что и найденный меньший. Это хороший вариант?

Это хороший вариант. 

Цитата(Merovingean @  8.7.2015,  22:49 Найти цитируемый пост)
В плане производительности.

В плане производительности - это весьма нелёгкий вопрос. Некогда я развлекался созданием поисковой системы, в которой проиндексированные слова и связанные с ними записи хранились в особом файле, собиравшемся по-новой при переиндексации. На определённом этапе возникла задача объединения двух таких файлов в один, и была написана программа, которая могла объединять всего два файла в один. Спустя некоторое время я переписал программу объединения, чтобы она могла обрабатывать сразу несколько файлов. Но увы, народ, работавший с предыдущей версией, пожаловался, что новая версия объединяла сразу несколько файлов значительно медленнее (в несколько раз), чем последовательное попарное слияние файлов. В чем там было дело, я не успел разобраться, но такой факт имел место быть.

Возможно, Вам не нужно на каждом этапе искать (среди имеющихся 1...500-2000 номеров) наименьший номер (это как раз потеря производительности), Вам нужно хранить уже считанные (но несброшенные в окончательный файл из-за их ненаименьшести) из файлов номера в отсортированном списке. Когда Вы сбрасываете наименьший из номеров (который при отсортированности списка легко определяется), то вместо него (если файл ещё не закончился) Вы в список добавляете следующий номер из этого же файла, но не на старое место, а согласно сортировке. Если файл закончился, то он как бы выпадает из этого списка, уменьшая размер списка.

Возможно, и это все ерунда, а попарное слияние самое быстрое. Не знаю. Нужно ставить эксперименты, нужно анализировать, считать количество сравнений и т.д. И ещё, просто одновременная работа с тысячей файлов (вне зависимости от сравнений) может сильно подтормаживать.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Merovingean
Дата 27.7.2015, 08:46 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.7.2015

Репутация: нет
Всего: нет



Вопрос решил примерно следующим образом:

Код

std::vector<ifstream> file_streams(stream_count);  

using int_and_stream = std::pair<int, std::ifstream&>;
using cont = std::list<int_and_stream>;
std::priority_queue<int_and_stream, cont, pair_comparer> queue;

for(auto& stream: file_streams)
{
   int id;
   if(stream >> id)
      queue.push(std::make_pair(id, stream));
}

while(!queue.empty())
{
   auto smallest = queue.top();
   outstream << smallest.first;
   int id;
   if(smallest.second >> id)
   {
      queue.push(std::make_pair(id, stream));
   }
}   


Код

class pair_comparer
{
public:
    bool operator()(std::pair<int, std::ifstream&> n1,std::pair<int, std::ifstream&> n2)
{
        return n1.first > n2.first;
    }
};


Это сообщение отредактировал(а) Merovingean - 28.7.2015, 08:47
PM MAIL   Вверх
feodorv
Дата 28.7.2015, 04:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Merovingean, красиво же)))

PS А вдруг пустой input-файл попадётся?

Добавлено через 4 минуты и 23 секунды
Туплю, но почему second'ы сравниваются?


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Merovingean
Дата 28.7.2015, 08:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.7.2015

Репутация: нет
Всего: нет



Цитата(feodorv @ 28.7.2015,  04:25)
Merovingean, красиво же)))

PS А вдруг пустой input-файл попадётся?

Добавлено @ 04:29
Туплю, но почему second'ы сравниваются?

Поправил.
Писал на память и упустил пару моментов. В моем случае все немного сложнее и вместо номеров UUID. Но смысл не меняется.

Куда более серьезная проблема в том, что код не универсален - система не даст открыть любое количество файлов.
PM MAIL   Вверх
xvr
Дата 28.7.2015, 11:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(Merovingean @  28.7.2015,  08:51 Найти цитируемый пост)
Куда более серьезная проблема в том, что код не универсален - система не даст открыть любое количество файлов. 

Это не большая проблема - сливайте по несколько файлов зараз (сколько даст открыть система), потом сливайте файлы результаты от первого шага. Если их будет слишком много - опять делите на пачки и сливаете. Получается дерево слияния файлов.

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0947 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.