Совпадение строки; алгоритмический вопрос

Общие вопросы программирования, алгоритмы и т.п.

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

Совпадение строки; алгоритмический вопрос

Сообщение hinst » 16.07.2014 14:59:43

Пытаюсь придумать как лучше реализовать следующее:
Чтобы был класс который определяет когда произошло вхождение подстроки в строку, причём символы текста, в котором надо искать подстроку, подаются по одному
Код: Выделить всё
TSearcher = class
public
  constructor Create(aDesired: string);
  function Match(c: Char): Boolean;
end;

При этом у класса будет много раз вызываться метод Match, и он должен вернуть True когда в подстроке он достиг конца искомого слова
Код: Выделить всё
for i := 1 to Length(s) do
  if searcher.Match(s[i]) then
    WriteLN('Found desired str at #', i);

До решения "в лоб", которое заключается в том, чтобы сохранять последние Length(aDesired) символов в поле TSearcher'а и каждый раз "прокручивать" влево буфер, вставлять в конец символ и сравнивать BackLog = Desired я уже додумался, но вычислительная сложность такого решения будет не самая лучшая.
Идеи? предложения? плз
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38


Re: Совпадение строки; алгоритмический вопрос

Сообщение runewalsh » 17.07.2014 23:30:55

Такая идея. Ведём список потенциальных соответствий (ПС) — сколько символов начиная с некоторой позиции уже подошло. С новым символом каждое активное ПС либо убивается сразу, если символ не подошёл, либо удлиняется на 1 и, если длина достигла длины образца, тоже убивается и выставляет результат. А если символ соответствует первому символу образца, открывается новое ПС.

Это если тебе при поиске "ee" в "eeeeee" нужны 5 соответствий, а не 3. Из постановки задачи так и есть, просто если 3, то всё вообще тривиально.

Код: Выделить всё
{$mode objfpc}

type
  TSearcher = class
  public
    constructor Create(aDesired: string);
    function Match(c: Char): Boolean;
  private
    desired: string;
    nTrack: integer;
    track: array of integer;
  end;

  constructor TSearcher.Create(aDesired: string);
  begin
    Assert(aDesired <> '');
    desired := aDesired;
    SetLength(track, length(aDesired) - 1);
    nTrack := 0;
  end;

  function TSearcher.Match(c: Char): Boolean;
  var
    i: integer;
    keep: boolean;
  begin
    result := false;
    for i := nTrack - 1 downto 0 do
    begin
      inc(track[i]);
      keep := c = desired[track[i]];
      if keep and (track[i] = length(desired)) then
      begin
        keep := false;
        result := true;
      end;

      if not keep then
      begin
        track[i] := track[nTrack - 1];
        dec(nTrack);
      end;
    end;

    if c = desired[1] then
      if length(desired) = 1 then result := true else
      begin
        inc(nTrack);
        track[nTrack - 1] := 1;
      end;
  end;

var
  s: TSearcher;
  c: char;

begin
  s := TSearcher.Create('needle');
  try
    for c in 'why should you search a needle in a haystack man' do
    begin
      writeln('put(', c, ') = ', s.Match(c));
    end;
  finally
    s.Free;
  end;
end.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Re: Совпадение строки; алгоритмический вопрос

Сообщение Kemet » 18.07.2014 11:48:20

Не совсем удачное решение, передавать строку, в которой нужно найти образец по одному символу, лучше передать строку, тем более, что это все равно указатель, и строка не копируется. А потом уже искать подстроку, и, в случае неудачи на какой-то итерации, перейдя к следующей и, в случае нахождения например первого символа образца, проверить соответствие последнего, если совпала - имеет смысл сравнивать содержимое образца, что существенно ускорит поиск, а если передавать строку по символу, то так не получится, да и оверхед по вызовам и реаллокации строки
Kemet
постоялец
 
Сообщения: 241
Зарегистрирован: 10.02.2010 19:28:32
Откуда: Временно оккупированная территория


Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 18

Рейтинг@Mail.ru