Russian Qt Forum

Программирование => Алгоритмы => Тема начата: fa от Сентябрь 13, 2009, 10:48



Название: Быстрый алгоритм поиска одинаковых строк
Отправлено: fa от Сентябрь 13, 2009, 10:48
Здравствуйте, необходим быстрый алгоритм поиска одинаковых строк фиксированной длины в файле.

Говоря более конкретно:
имеется файл примерно с таким содержанием:
Код:
A0FE3CFD
33E33492
6F71C7BE
3107BBA2
D504D497
BC8093F5
B0799820
C131EADA
338EC808
BC8093F5
040D900F
4B9C482A
7E0E1E10
ABA9DA9A
88D6CF18
ABA9DA9A
73B459C3

На выходе надо получить примерно такой файл:
Код:
Total: 4
ABA9DA9A - 2
BC8093F5 - 2

Спасибо.


Название: 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
можно вот здесь подробнее?

Код
C++ (Qt)
bool validNumber;
QString strVal = file.readLine();
quint32 val = strVal.toInt( &validNumber, 16 );
 


Название: Re: Быстрый алгоритм поиска одинаковых строк
Отправлено: MoPDoBoPoT от Сентябрь 13, 2009, 14:10
Да и как-то вычислять значение хэша от значения хэша =)))))
Раз хэш(HEX-код), то
Код
C++ (Qt)
bool validNumber;
QString strVal = file.readLine();
quint32 val = strVal.toInt( &validNumber, 16 );
 
+1


Название: 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 )
{
  int i, beg = 0, limit = lst.size();
  for (i = 1; i < limit; ++i) {
    if (lst[i] != lst[beg]) {
     if (i - beg > 1)
       cout << lst[beg] << " - " << (i - beg) << endl;
     beg = i;
   }
  }
  if (limit - beg > 1)
    cout << lst[beg] << " - " << (limit - beg) << endl;
}


Название: Re: Быстрый алгоритм поиска одинаковых строк
Отправлено: BRE от Сентябрь 13, 2009, 14:51
Пусть есть отсортированный QList<int>.
Но его нет.
Что бы его получить нужен дополнительный проход по всем элементам + сортировка.


Название: Re: Быстрый алгоритм поиска одинаковых строк
Отправлено: Igors от Сентябрь 13, 2009, 14:59
Пусть есть отсортированный QList<int>.
Но его нет.
Что бы его получить нужен дополнительный проход по всем элементам + сортировка.
Не понял насчет дополнительного прохода. Прочитали из файла в QList, затем

qSort(lst.begin(), lst.end());

Если в память лезет, то все просто


Название: Re: Быстрый алгоритм поиска одинаковых строк
Отправлено: BRE от Сентябрь 13, 2009, 15:02
Не понял насчет дополнительного прохода. Прочитали из файла в QList, затем

qSort(lst.begin(), lst.end());

Если в память лезет, то все просто
1 проход: цикл загрузки 25 млн элементов в QList
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( ключ есть в хеше )
   {
      увеличили счетчик повторов у элемента из хеша
      занесли ключ в repList
   }   
Только не просто if( ключ есть в хеше ), а if( ключ есть и значение "количество повторов" ==1  ), иначе при количестве повторов>2 список epList будет содержать повторы.


Название: 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))       // спуск по дереву
  ++hash[key];                 // еще 1 спуск по дереву
else
  hash.insert(key, 0);        // вызов new и балансировка дерева

Откуда же возьмется скорость?  :)


Название: 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
Погонял тесты, посмотрел. Чтение и перевод из строки в число выполнял одинаковый код.
Предварительные результаты следующие:
При отсутствии совпадений по скорости выигрывает алгоритм с сортировкой, но с увеличением количества совпадающих строк (и увеличением количества попаданий в хеш) алгоритм с хешем  (использовался QHash) догоняет, а затем и перегоняет первый.
Все то же самое должно быть и по памяти. При небольшом числе совпадений сортировка съест в 3-4 раза меньше, но если все строки одинаковы... :) Зато с сортировкой голова не болит "какие там данные"


Название: Re: Быстрый алгоритм поиска одинаковых строк
Отправлено: BRE от Сентябрь 14, 2009, 17:19
Все то же самое должно быть и по памяти. При небольшом числе совпадений сортировка съест в 3-4 раза меньше, но если все строки одинаковы... :) Зато с сортировкой голова не болит "какие там данные"
Чем больше совпадений, тем меньше элементов будет храниться в хеше (тем меньше памяти понадобиться).
Для сортировки - не важно сколько будет повторов, все элементы будут загружены в память.


Название: Re: Быстрый алгоритм поиска одинаковых строк
Отправлено: fa от Сентябрь 14, 2009, 20:17
1) Правильно ли я понял, что строки не только фиксированной длины, но являются 16-чным представлением целых 32-битных чисел?
2) Правильно ли я понял, что  кол-во строк(чисел) гарантированно не превышает 1024*1024*256 = 67'108'864;
1-ое: верно.
2-ое: теоретически может быть и больше...

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

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


Название: Re: Быстрый алгоритм поиска одинаковых строк
Отправлено: spectre71 от Сентябрь 14, 2009, 21:04
1) Правильно ли я понял, что строки не только фиксированной длины, но являются 16-чным представлением целых 32-битных чисел?
2) Правильно ли я понял, что  кол-во строк(чисел) гарантированно не превышает 1024*1024*256 = 67'108'864;
1-ое: верно.
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
Цитировать
Красивый алгоритм (и полезный сайт)
Памяти правда сожрет больше, ну так это "диалектика"
больше, чем ... ???
Например алгоритм quicksort не требует дополнительной памяти, т.е. требуется память только под сам массив сортируемых данных.
Алгоритм поразрядной сортировки(вторая ссылка из которых я  приводил), требует дополнительную память в размере исходного массива + еще немного для хранения счетчиков для разряда; - размер памяти под счетчики зависит от 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 можно сделать и без рекурсии, тогда неюбходимо эмулировать стек и выделять память в куче.