Паскаль

Вас приветствует клуб программистов!

Клуб программистов

Стартовая  :: Главная :: Гостевая ::  Форум ::  Чат :: Delphi :: Ассемблер:: C&C++ ::  Базы данных :: Web :: Алгоритмы :: Сети

Общение:

СТАТЬЯ:

Форум

Чат

Поиск 

  Линейный поиск

     Пусть дан массив элементов A и ключ b. Для b необходимо найти совпадающий с ним элемент массива А. Линейный поиск подразумевает последовательный просмотр всех элементов массива А в порядке их расположения, пока не найдется элемент равный b. Если заранее неизвестно, имеется данный элемент в массиве или нет, то необходимо следить за тем, чтобы поиск не вышел за границы массива, что достигается использованием стоппера (барьерного элемента). Рассмотрим 2 примера:

1)без использования стоппера

const N=10;

type Any=integer;

var A:array[0..N-1] of Any;

    i:integer;

    b:Any;

begin

  writeln('Введите элементы массива:');

   for i:=0 to N-1 do

    readln(A[i]);

  write('Введите ключ:');

  readln(b);

  i:=0;

   while (i<>N) and (A[i]<>b) do

    i:=i+1;

  if i<>N then 

   writeln('Элемент, совпадающих с ключом, найден. Позиция элемента -',i+1)

          else 

   writeln('Элементов, совпадающих с ключом, нет');

end.

2) с использованием стоппера

const N=11;

type Any=integer;

var A:array[0..N] of Any;

    i:integer;

    b:Any;

begin

  writeln('Введите элементы массива:');

   for i:=0 to N-1 do

    readln(A[i]);

  write('Введите ключ:');

  readln(b);

   A[N]:=b; {стоппер}

  i:=0;

    while A[i]<>b do

      i:=i+1;

  if i<>N then 

   writeln('Элемент, совпадающих с ключом, найден. Позиция элемента -',i+1)

          else 

   writeln('Элементов, совпадающих с ключом, нет');

end.

     Следует отметить, что в общем случае при линейном поиске среди N элементов требуется в среднем N/2 сравнений в случае успешного поиска и N сравнений в наихудшем случае, и затраты времени для больших массивов поэтому велики.

     Применяется данный алгоритм, если никакой дополнительной информации о данных массива нет.

Бинарный поиск

    Очевидно, что нельзя каким-либо способом ускорить поиск, если отсутствует информация о данных, среди которых производится поиск. Также известно, что если данные упорядочены, то поиск можно сделать значительно эффективнее. Поэтому рассмотрим алгоритм, который основан на том, что массив A упорядочен (т. е. a[i-1]<=a[i] при 1<=i<N).

     Суть: берут средний элемент массива и сравнивают его с ключом. В результате возможны 3 случая:

1) если элемент массива равен ключу, то искомый элемент найден;

2)если элемент массива меньше ключа, то все элементы массива с индексами, которые меньше N/2 исключаются из рассмотрения;

3)если элемент массива больше ключа, то все элементы массива с индексами, которые больше N/2 исключаются из рассмотрения;

     Затем поиск продолжается в одной из половин массива аналогичным образом.

const N=10;

type Any=integer;

var A:array[0..N] of Any;

    Left,Right,m,i,j:integer;

    b:Any;

begin

  writeln('Введите упорядоченную последовательность эл-тов массива ');

    for i:=0 to N do readln(A[i]);

     writeln('Введите ключ');

  readln(b);

   Left:=0;Right:=N;

    while Left<Right do

     begin

      m:=(Left+Right) div 2;

      if A[m]<b then Left:=m+1

                else Right:=m;

     end;

   if (Right<>N) or ((Right=N) and (a[N]=b)) then 

      writeln('Эл-т найден. Позиция эл-та: ',Right)

                                              else 

      writeln('Элемента нет');

end.

     Нахождение элемента бинарным поиском осуществляется очень быстро. При поиске среди N элементов требуется log2(N) сравнений в наихудшем случае. Кроме того, бинарный поиск уже при N порядка 100 значительно эффективнее линейного - как по скорости обнаружения, так и по способности к получению отрицательного результата. Для доказательства этого приведу следующие характеристики линейного и бинарного поиска:

1) линейный поиск:

количество элементов:10

среднее количество сравнений при наличии элемента:5

количество сравнений при отсутствии элемента:10

количество элементов:1000

среднее количество сравнений при наличии элемента:500

количество сравнений при отсутствии элемента:1000

количество элементов:1000000

среднее количество сравнений при наличии элемента:500000

количество сравнений при отсутствии элемента:1000000

1) бинарный поиск:

количество элементов:10

максимальное количество сравнений при наличии элемента:8

максимальное количество сравнений при отсутствии элемента:8

количество элементов:1000

максимальное количество сравнений при наличии элемента:10

максимальное количество сравнений при отсутствии элемента:10

количество элементов:1000000

максимальное количество сравнений при наличии элемента:20

максимальное количество сравнений при отсутствии элемента:20

Интерполяционный поиск

     Представим себе поиск слова в словаре. Маловероятно, что мы сначала заглянем в середину словаря, затем отступим от начала на 1/4 или 3/4 и т.д, как в бинарном поиске.

     Если нужное слово начинается с буквы 'А', то и поиск имеет смысл начинать в начале словаря. Когда же найдена отправная точка для поиска, дальнейшие действия будут мало похожи на рассмотренные выше методы.

    Мы приходим к алгоритму, называемому интерполяционным поиском. Пусть задан массив записей R1,R2,..Rk, снабженных соответственно ключами K1,K2,..Kn. Необходимо найти запись с данным ключом K. Тогда, если известно, что K лежит между Kl и Ku, то следующую пробу делаем примерно на расстоянии (u-l)*(K-Kl)/(Ku-Kl) от l, предполагая, что ключи являются числами, возрастающими приблизительно как арифметическая прогрессия.

     Интерполяционный поиск требует в среднем около log2 log2 N шагов, и поэтому он предпочтительнее бинарного при работе с большими массивами.

Поиск подстроки в строке.

Пусть дана строка s и подстрока p. Тогда для поиска подстроки p в строке s возможно использование следующего алгоритма:

var s,p:string;

    i,j,lp,ls:integer;

begin

{Ввод строки и подстроки}

   writeln('Введите строку');

   readln(s);

   ls:=length(s);

   writeln('Введите подстроку');

    readln(p);

    lp:=length(p);

{Поиск подстроки в строке}

    i:=0;

      repeat

       i:=i+1;

       j:=1;

         while (j<lp) and (s[i+j]=p[j]) do

           j:=j+1;

      until (j=lp) or (i=lp-ls) or (i>ls);

       if (j=lp) and (lp<>1) then writeln('Подстрока в строке есть');

       if i<>ls then writeln('Подстроки в строке нет');

end.

     Алгоритм является эффективным, если несовпадение символов строки и подстроки происходит после нескольких сравнений во внутреннем цикле. Но, если совпадение обнаружено в конце строки, то требуется lp*ls сравнений.

Алгоритм Кнута, Морриса и Пратта (КМП)

     Этот алгоритм был создан в 1970 году и получил свое название от имен его разработчиков. Он состоит из двух этапов: подготовительного и основного.

     На подготовительном этапе учитывается структура подстроки. Для этого формируется массив D, в котором учитывается совпадения символов подстроки с началом подстроки следующим образом: нулевой элемент массива D получает значение равное -1. Далее для каждой позиции j, совпадающей с началом подстроки, вычисляется максимальное количество предшествующих ей символов. Если же совпадений нет, то соответствующий элемент массива D равен -1. Размерность массива D равна длине подстроки.

     Теперь рассмотрим основной этап. Поиск начинается со сравнения первого символа строки с первым символом подстроки. В случае несовпадения происходит сдвиг подстроки на количество символов, указанных соответствующим элементом массива D. Если совпадения подстроки со строкой не будет  (то есть данной подстроки в строке нет), то программа выйдет из цикла для поиска подстроки, когда i будет равняться длине строки, то есть если ни один символ подстроки не совпадает ни с одним символом строки, то программа выполнит N сравнений, если же совпадения отдельных элементов подстроки(но не всей подстроки со строкой) будут найдены, то в наихудшем случае потребуется N+M сравнений. Если же совпадение подстроки со строкой обнаружится сразу, то потребуется M cравнений.

uses Crt;

const Mmax=100;

Nmax=10000;

Esc=#27;

var I, J, K, L, M, N : integer;

    Ch : char;

    P : array [0..Mmax-1] of char;

    S : array [0..Nmax-1] of char;

    D : array [0..Mmax-1] of integer;

begin

  write('Введите строку');

  N := 0; Ch := ReadKey;

  While (Ch<>#13) and (N<Nmax-1) do

   begin

     write(Ch); 

     S[N] := Ch; 

     N:=N+1; 

     Ch := ReadKey

   end;

  writeln;

  write('Введите подстроку');

  M := 0;

  Ch := ReadKey;

   While (Ch<>#13) and (M<Mmax-1) do

     begin

       write(Ch); 

       P[M] := Ch;  

       m:=m+1;

       Ch := ReadKey;

     end;

  writeln;

  write('Поиск подстроки : ');

   if Ch=Esc then Exit;

   J := 0; K := -1; D[0] := -1;

    while J < M-1 do

     begin

      while (K >= 0) and (P[J]<>P[K]) do

        K := D[K];

      J:=J+1;

      K:=K+1;

       if P[J]=P[K] then D[J] := D[K] 

                    else D[J] := K;

     end;

   J := 0;

   I := 0;

   K := 0;

    while (J<M) and (I<N) do

      begin

       while K<=I do 

         begin 

           Write(S[K]); 

           K:=K+1;

         end;

       while (J>=0) and (S[I]<>P[J]) do 

          J := D[J];

       I:=I+1; J:=J+1;

      end;

   writeln;

   if J = M then writeln('Образец в строке присутствует')

            else writeln('Образец в строке отсутствует');

end.

Обратная связь:

 Гостевая

Авторам

Рейтинг сайта:

Рейтинг@Mail.ru   

Web-KatoK TOP100!

   be number one        

Chelyabinsk Online