Название: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 13, 2009, 10:48 Здравствуйте, необходим быстрый алгоритм поиска одинаковых строк фиксированной длины в файле.
Говоря более конкретно: имеется файл примерно с таким содержанием: Код: A0FE3CFD На выходе надо получить примерно такой файл: Код: Total: 4 Спасибо. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Igors от Сентябрь 13, 2009, 11:58 Добрый день
- загружаете все строки - сортируете - удаляете одинаковые строки из сортированного массива (здесь же подсчитываете число вхождений) Наверное я не понял вопроса :) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 13, 2009, 12:03 Дело в том, что строк во водном файле будет порядка 25млн.
И надо добиться как можно меньшего времени поиска ;) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: MoPDoBoPoT от Сентябрь 13, 2009, 12:11 Первое что пришло на ум - использовать хэш строк.
QHash< хэш_строки, QPair<строка, количество_повторов> > Чтобы QHash шустрее работал, надо зарезервировать необходимое место. Это можно прикинуть исходя из того, что длины строк одинаковой длины. ---- UPD: строк во входном файле будет порядка 25млн :o Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 13, 2009, 12:41 Да, я пробовал сейчас через хэш, правда функцию расчета вручную задал =)
Другой вопрос будет ли он работать корректно? потому что значение способом тотального сравнения строк и через сравнение хэшей получается разный О.о Да и как-то вычислять значение хэша от значения хэша =))))) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Igors от Сентябрь 13, 2009, 13:16 Дело в том, что строк во водном файле будет порядка 25млн. Давайте прикинем. 8 байт строка + 4 байта счетчик. 25 * 12 = 300 MbИ надо добиться как можно меньшего времени поиска ;) Это по нынешним временам не так уж много. Но это уже "объем", поэтому лучше использовать примитивные структуры struct CStr { // не делайте деструктор, сортировка будет его все время звать bool operator == ( const CStr & ) const; bool operator < ( const CStr & ) const; int mCount; char mData[8]; // не QString, слишком жирно }; Читаете все в QList, сортируете его. Удаление строк (erase) лучше на таких объемах избегать - сразу пишете в выходной файл. Если же "не лезет в память" - то это другая задача, нужно определиться. Edit: без счетчика можно спокойно обойтись, получать его на выходе Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 13, 2009, 13:36 Строка это текстовое представление 32-битного числа. Проще строку переводить в число при загрузке и хранить число, так же его можно использовать в качества ключа для хэша.
Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 13, 2009, 13:45 Цитировать Если же "не лезет в память" - то это другая задача, нужно определиться. для этого выход есть, можно разбить исходный файл на 16 по первому символу.Цитировать Проще строку переводить в число при загрузке и хранить число, так же его можно использовать в качества ключа для хэша. можно вот здесь подробнее?Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 13, 2009, 13:54 можно вот здесь подробнее? Код
Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: MoPDoBoPoT от Сентябрь 13, 2009, 14:10 Да и как-то вычислять значение хэша от значения хэша =))))) Раз хэш(HEX-код), тоКод
Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 13, 2009, 14:21 QHash<quint32, int> hash; // Сам контейнер (ключ-количество повторений)
QList<quint32> repList; // Список ключей с количеством повторений > 1 Цикл по всем строкам { читаемСтроку получилиКлюч if( ключ есть в хеше ) { увеличили счетчик повторов у элемента из хеша занесли ключ в repList } else { добавили ключ в hash. Количество повторов = 1 } } Дальше просмотрев список repList сможем получить все ключи которые встретились > 1 раза. Для получения точного числа повторов для указанного ключа лезим в hash. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Igors от Сентябрь 13, 2009, 14:24 Строка это текстовое представление 32-битного числа. Проще строку переводить в число при загрузке и хранить число, Верно, памяти в 2 раза меньшетак же его можно использовать в качества ключа для хэша. А зачем здесь вообще какой-то хэш? Пусть есть отсортированный QList<int>. Код: void PrintDups( QList<int> & lst ) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 13, 2009, 14:51 Пусть есть отсортированный QList<int>. Но его нет.Что бы его получить нужен дополнительный проход по всем элементам + сортировка. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Igors от Сентябрь 13, 2009, 14:59 Пусть есть отсортированный QList<int>. Но его нет.Что бы его получить нужен дополнительный проход по всем элементам + сортировка. qSort(lst.begin(), lst.end()); Если в память лезет, то все просто Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 13, 2009, 15:02 Не понял насчет дополнительного прохода. Прочитали из файла в QList, затем 1 проход: цикл загрузки 25 млн элементов в QListqSort(lst.begin(), lst.end()); Если в память лезет, то все просто 2 проход: сортировка 25 млн элементов qSort 3 проход: цикл по 25 млн элементов для получения результата Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 13, 2009, 15:18 Цитировать 1 проход: цикл загрузки 25 млн элементов в QList именно,2 проход: сортировка 25 млн элементов qSort 3 проход: цикл по 25 млн элементов для получения результата упор должен быть на скорость, а не простоту реализации Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: MoPDoBoPoT от Сентябрь 13, 2009, 15:22 if( ключ есть в хеше ) Только не просто if( ключ есть в хеше ), а if( ключ есть и значение "количество повторов" ==1 ), иначе при количестве повторов>2 список epList будет содержать повторы.{ увеличили счетчик повторов у элемента из хеша занесли ключ в repList } Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 13, 2009, 15:51 Только не просто if( ключ есть в хеше ), а if( ключ есть и значение "количество повторов" ==1 ), иначе при количестве повторов>2 список epList будет содержать повторы. Уточню:if( ключ есть в хеше ) { увеличили счетчик повторов у элемента из хеша if( количество повторов == 2 ) занесли ключ в repList } Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Igors от Сентябрь 13, 2009, 16:10 Цитировать 1 проход: цикл загрузки 25 млн элементов в QList именно,2 проход: сортировка 25 млн элементов qSort 3 проход: цикл по 25 млн элементов для получения результата упор должен быть на скорость, а не простоту реализации Городить что-то с QHash имеет смысл если Вы уверены/гарантируете что повторов будет достаточно много. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 13, 2009, 16:44 Цитировать Городить что-то с QHash имеет смысл если Вы уверены/гарантируете что повторов будет достаточно много. общий смысл задачи состоит в том, чтобы статистическими методами выявить наиболее эффективные алгоритма подсчета контрольных сумм... по устойчивости к коллизиям и времени.я не думаю что корректно вообще поиск через хэш делать... Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Igors от Сентябрь 13, 2009, 16:58 я не думаю что корректно вообще поиск через хэш делать... Я тоже так не думаю. Пользоваться всеми этими контейнерами удобно и приятно, но для больших данных они не очень подходят - скорости нет. НапримерКод: if (hash.contains(key)) // спуск по дереву Откуда же возьмется скорость? :) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Tonal от Сентябрь 14, 2009, 08:13 2 Igors Учи матчасть. Хеш - это не дерево, это хешь. :)
Т.е. для поиска трудоёмкость константа, как и в массиве по индексу: О(1). Но для вставки там может быть О(n). А вот для дерева и вставка и поиск О(log n) Так что при большом количестве уникальных значений дерево (QMap) может оказаться выгоднее. Ну и всяко нужно ключи в int переводить. :) Можно даже свою функцию написать, табличную, чтоб не тормозили выбор системы счисления и локали. :) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 14, 2009, 08:27 Если нужна скорость, то нужно не предполагать что будет быстрее, а реализовать и погонять тесты. Посмотреть в профилировщике, что откушивает большую часть процессорного времени.
Попробовать разные контейнеры (думаю что stl-ные будут быстрее), возможно придется написать для них свой аллокатор памяти (если выясниться, что торможение происходит на выделении памяти) и т.д. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Tonal от Сентябрь 14, 2009, 08:59 Это всяко. :)
Но таки характеристики алгоритмов знать нужно. Например брать в качестве контейнера массив и искать там тупым перебором, для таких объёмов смысл имеет только для получения наихудшего случая. :) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 14, 2009, 09:00 Это всяко. :) +мульен. :)Но таки характеристики алгоритмов знать нужно. Например брать в качестве контейнера массив и искать там тупым перебором, для таких объёмов смысл имеет только для получения наихудшего случая. :) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: spectre71 от Сентябрь 14, 2009, 10:40 Здравствуйте, необходим быстрый алгоритм поиска одинаковых строк фиксированной длины в файле. Говоря более конкретно: имеется файл примерно с таким содержанием: ... ... Спасибо. 1) Правильно ли я понял, что строки не только фиксированной длины, но являются 16-чным представлением целых 32-битных чисел? 2) Правильно ли я понял, что кол-во строк(чисел) гарантированно не превышает 1024*1024*256 = 67'108'864; Если это так, то могу привести быстрый линейный алгоритм для чтения и сортировки(или определение кол-ва дубликатов). Если это не так, то уточни параметры задачи Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Igors от Сентябрь 14, 2009, 12:13 2 Igors Учи матчасть. Хеш - это не дерево, это хешь. :) Каюсь, изучать внутренности стандартных классов не люблю :). Текст всегда довольно развесистый и тяжелый. Но даже в лучшем случае (дерево) это совсем недешево на миллионах данных.Т.е. для поиска трудоёмкость константа, как и в массиве по индексу: О(1). Но для вставки там может быть О(n). А вот для дерева и вставка и поиск О(log n) Конкретно для QHash все гораздо хуже (посмотрел). Он бьет данные на bucket'ы, умеет по ключу спрыгнуть на bucket а внутри него - увы, прямой перебор. В какой-то момент он ре-организует bucket'ы. В общем по скорости - полный завал. Хотя будет хорошо работать если данные "одни повторы". Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Igors от Сентябрь 14, 2009, 12:14 Если нужна скорость, то нужно не предполагать что будет быстрее, а реализовать и погонять тесты. Дело. Давайте выложим каждый по своему варианту и сравним?Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: spectre71 от Сентябрь 14, 2009, 12:30 Дело. Давайте выложим каждый по своему варианту и сравним? Не надо страдать фигней. Пусть fa ответит по поводу ограничений на входные данных для своей задачи! Если верно, то что я писал выше, учитывая кол-во чисел(строк) >1'000'000 - однозначно алгоритм поразрядной сортировки. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 14, 2009, 16:05 Погонял тесты, посмотрел. Чтение и перевод из строки в число выполнял одинаковый код.
Предварительные результаты следующие: При отсутствии совпадений по скорости выигрывает алгоритм с сортировкой, но с увеличением количества совпадающих строк (и увеличением количества попаданий в хеш) алгоритм с хешем (использовался QHash) догоняет, а затем и перегоняет первый. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 14, 2009, 16:08 однозначно алгоритм поразрядной сортировки. +1Думаю что линейный алгоритм с меньшим количеством проходов не оставит шансов двум проверенным алгоритмам. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Igors от Сентябрь 14, 2009, 17:06 Погонял тесты, посмотрел. Чтение и перевод из строки в число выполнял одинаковый код. Все то же самое должно быть и по памяти. При небольшом числе совпадений сортировка съест в 3-4 раза меньше, но если все строки одинаковы... :) Зато с сортировкой голова не болит "какие там данные"Предварительные результаты следующие: При отсутствии совпадений по скорости выигрывает алгоритм с сортировкой, но с увеличением количества совпадающих строк (и увеличением количества попаданий в хеш) алгоритм с хешем (использовался QHash) догоняет, а затем и перегоняет первый. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: BRE от Сентябрь 14, 2009, 17:19 Все то же самое должно быть и по памяти. При небольшом числе совпадений сортировка съест в 3-4 раза меньше, но если все строки одинаковы... :) Зато с сортировкой голова не болит "какие там данные" Чем больше совпадений, тем меньше элементов будет храниться в хеше (тем меньше памяти понадобиться).Для сортировки - не важно сколько будет повторов, все элементы будут загружены в память. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 14, 2009, 20:17 1) Правильно ли я понял, что строки не только фиксированной длины, но являются 16-чным представлением целых 32-битных чисел? 1-ое: верно.2) Правильно ли я понял, что кол-во строк(чисел) гарантированно не превышает 1024*1024*256 = 67'108'864; 2-ое: теоретически может быть и больше... уточняю условия задачи. берется файл абсолютно любого размера, для каждых его 128 байт считается значение контрольной суммы и записывается в файл. и теперь осуществляется поиск одинаковых строк в файле. соответственно количество строк = размер файла / 128 Но я думаю поразрядная сортировка это оптимальный вариант, вряд ли наберется 67млн строк, к тому же есть вариант записывать при подсчете коллизий в 16 файлов, сортируя по первому символу... заранее зная первый символ можно еще более увеличить скорость поиска =) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: spectre71 от Сентябрь 14, 2009, 21:04 1) Правильно ли я понял, что строки не только фиксированной длины, но являются 16-чным представлением целых 32-битных чисел? 1-ое: верно.2) Правильно ли я понял, что кол-во строк(чисел) гарантированно не превышает 1024*1024*256 = 67'108'864; 2-ое: теоретически может быть и больше... уточняю условия задачи. берется файл абсолютно любого размера, для каждых его 128 байт считается значение контрольной суммы и записывается в файл. и теперь осуществляется поиск одинаковых строк в файле. соответственно количество строк = размер файла / 128 Понятно. Если не сложно, объясни почему именно по 128 байт, а не больше, что за задача? Далее, сильно расписывать не буду, спать уже хочся :), если что непонятно потом спросишь. 1) Имеем файл с 32-рарядными числами в 16-чной текстовой записи. Каздое число на новой стоке. Вопрос! Ты формируешь файл? Если ты, то пиши без данные без прерноса строк, а лучше в бинарном виде, а не в 16-чной текстовой записи. 2) Читаем файл, лучше для скорости!!! не пользоваться QT-ми строками для чтения и преобразования данных, а читать в буфер, разбирать и преобразовывать самостоятельно. 3) Для сортировки будем использовать алгоритм поразрядной сортировки. Изучи это: a) http://www.codelab.ru/task/4 (http://www.codelab.ru/task/4) и это b) http://www.codelab.ru/task/5/ (http://www.codelab.ru/task/5/) 4) Нам оптимальнее всего выделить 2 разряда по 2 байта(high и low), соответственно при чтении каждого числа заполняем такой массив qint16 order[2]; // order[0] - high; order[1] - low; 5) Если файл слишком большой, то читаем и сортируем "кусками", пишем отсортированные данные для каждого куска в свой файл, а затем объединяем за линейное время. 6) Размер выделяемой памяти под "кусок" тебе понадобится 256 KB(под счетчики) + 2*4*N байт, где N кол-во чисел для сортировки 7) 4*N байт - под массив N вышеописанных массовов(qint16 order[2]) 8.) Еще 4*N, для копирования данных после сортировки по первому разряду(см. алгоритмы, тебе нужен будет (b)) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 14, 2009, 21:25 Если не сложно, объясни почему именно по 128 байт, а не больше, что за задача? Почему-то было решено сделать именно так. решал не я ))..задача состоит в проверке эффективности алгоритмов вычисления контрольных сумм на основе статистики. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: spectre71 от Сентябрь 14, 2009, 21:48 Если не сложно, объясни почему именно по 128 байт, а не больше, что за задача? Почему-то было решено сделать именно так. решал не я ))..задача состоит в проверке эффективности алгоритмов вычисления контрольных сумм на основе статистики. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 15, 2009, 10:13 Каких конкретно алгоритмов вычисления контрольных сумм? А вот тут уже никакой конкретики, они приходят и уходят... Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: Igors от Сентябрь 15, 2009, 19:51 3) Для сортировки будем использовать алгоритм поразрядной сортировки. Изучи это: Красивый алгоритм (и полезный сайт)a) http://www.codelab.ru/task/4 (http://www.codelab.ru/task/4) и это b) http://www.codelab.ru/task/5/ (http://www.codelab.ru/task/5/) Памяти правда сожрет больше, ну так это "диалектика" :) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 16, 2009, 23:44 Цитировать Красивый алгоритм (и полезный сайт) больше, чем ... ???Памяти правда сожрет больше, ну так это "диалектика" Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: spectre71 от Сентябрь 17, 2009, 10:45 Цитировать Красивый алгоритм (и полезный сайт) больше, чем ... ???Памяти правда сожрет больше, ну так это "диалектика" Алгоритм поразрядной сортировки(вторая ссылка из которых я приводил), требует дополнительную память в размере исходного массива + еще немного для хранения счетчиков для разряда; - размер памяти под счетчики зависит от sizeof разряда, например если разряд берем 1 байт, то 256*4=1 KB, а если 2 байт, то 256*256*4=256 KB (на мой взгляд лучший вариант брать разряд 2 байт) Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: fa от Сентябрь 17, 2009, 11:09 Цитировать Например алгоритм quicksort не требует дополнительной памяти, т.е. требуется память только под сам массив сортируемых данных. угу, спасибо =))Алгоритм поразрядной сортировки(вторая ссылка из которых я приводил), требует дополнительную память в размере исходного массива + еще немного для хранения счетчиков для разряда; - размер памяти под счетчики зависит от sizeof разряда, например если разряд берем 1 байт, то 256*4=1 KB, а если 2 байт, то 256*256*4=256 KB (на мой взгляд лучший вариант брать разряд 2 байт) но это не страшно ).. Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: garryHotDog от Март 21, 2010, 21:22 для поиска подстроки в строке использовал "Алгорит БМХ (Боейра Мура Хорпсула)"...бытсро, просто, есть исходники...кому надо пишите
Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: kamre от Май 06, 2010, 10:45 Например алгоритм quicksort не требует дополнительной памяти, т.е. требуется память только под сам массив сортируемых данных. Как это quicksort не требует? В лучшем случае O(log n) памяти нужно, в худшем O(n).Название: Re: Быстрый алгоритм поиска одинаковых строк Отправлено: spectre71 от Май 07, 2010, 09:38 Например алгоритм quicksort не требует дополнительной памяти, т.е. требуется память только под сам массив сортируемых данных. Как это quicksort не требует? В лучшем случае O(log n) памяти нужно, в худшем O(n).Да, это так. Но имелось ввиду выделение дополнительной памяти в куче. Хотя quicksort можно сделать и без рекурсии, тогда неюбходимо эмулировать стек и выделять память в куче. |