
- •1Введение
- •2Сортировки
- •2.1Сортировки массивов
- •2.2Сортировка простым включением
- •2.3Сортировка простым выбором
- •2.4Сортировка простым обменом
- •2.5Сравнение простых сортировок
- •2.6 Сортировка шелла
- •2.7Пирамидальная сортировка
- •2.8Быстрая сортировка
- •2.9Поиск медианы и квантилей
- •2.10Сравнение сортировок
- •3Поиск подстроки в строке
- •3.1Поиск в строке
- •3.2Простой поиск в строке
- •3.3Поиск в строке. Алгоритм боуера-мура
- •4Генерация перестановок
- •4.1Генерация перестановок последовательности натуральных чисел
- •4.2Генерация перестановок элементов в антилексикографическом порядке
- •4.3Генерация перестановок за одну транспозицию элементов
- •4.4Генерация перестановок за одну транспозицию соседних элементов
- •5Генерация подмножеств
- •5.1Генерация всех подмножеств множества
- •5.2Генерация m -элементных подмножеств множества натуральных чисел
- •Var m: integer; {Размер подмножества}
- •Var I, j, p: integer;
- •5.3Генрация k-компонентных выборок на множестве {0, 1}
- •Var k: integer; {Количество нулей в кортеже}
- •I: integer;
- •Var I, j, p: integer;
- •If Finish then Break {Exit};
- •6Генерация разбиений
- •6.1Разбиение целых чисел
- •Var I, j: integer;
- •Var j: integer;
- •Var I, j, k: integer;
- •Var d, l, Sum: integer;
- •6.2Разбиение множеств
- •/1, 2, 3/ И /4/ затем /1, 2/ и /3, 4/ и т.Д. }
- •I, j, k, r, s: integer;
- •If not Flag2 then
- •If Flag1 then
- •If Forvd[j] then { j движется вперед}
- •7Обходы бинарных деревьев
- •7.1Процедуры прохождения бинарных деревьев
- •8Поиск на бинарных деревьях
- •8.1Процедуры поиска на бинарных деревьях
- •Рекомендованная литература
3.3Поиск в строке. Алгоритм боуера-мура
Алгоритм Боуера-Мура (БМ алгоритм) предложен в 1975 г. Р. Боуером и Д. Муром. Основная идея алгоритма состоит в организации посимвольного сравнения элементов строки и слова (подстроки) начиная с конца слова.
Для организации поиска перед началом поиска искомое слово (подстрока) трансформируется в некоторую таблицу поиска. Для наглядности будем считать, что таблица состоит из двух строк.
В качестве элементов первой строки такой таблицы используется элементы кодовой таблицы в 128 символов ASCII или в 256 символов расширенной кодовой таблицы.
Вторая строка таблицы формируется следующим образом:
Для каждого символа таблицы, являющегося символом искомого слова, в таблицу заносится расстояние от самого правого вхождения этого символа в искомое слово до конца этого слова.
Исключение составляет последний символ искомого слова. Он не принимает участия в описанной выше обработке. Если подобный ему символ или символы есть внутри слова, то именно они принимают участие в обработке. Если подобных ему символов нет внутри слова, то последний символ слова обрабатывается как символ, не являющийся символом искомого слова.
Для каждого символа таблицы, не являющегося символом искомого слова, в таблицу заносится длина искомого слова.
Так, например, для искомого слова "информационные" для символа и задается расстояние 5, для символа н -расстояние 2, а для символа е – расстояние 14.
Фрагмент таблицы поиска, содержащий символы слова "информационные" имеет вид:
… |
а |
б |
… |
д |
е |
и |
к |
… |
м |
н |
о |
п |
р |
с |
… |
у |
ф |
ы |
… |
… |
7 |
14 |
|
14 |
14 |
5 |
14 |
|
14 |
2 |
4 |
14 |
9 |
14 |
|
14 |
11 |
1 |
|
Процесс поиска реализуется следующим образом.
Выполняется посимвольное сравнение элементов строки и искомого слова (подстроки), начиная с конца слова.
Если при посимвольном сравнении элементов строки и слова обнаружено расхождение между образом S и строкой P, т.е. имеет место условие S[i] <> P[j], то анализируется символ строки поиска S[i], для которого произошло несовпадение.
Если символ строки поиска S[i] входит в образ P, то образ P сразу сдвигается вправо относительно строки поиска S на количество позиций, соответствующих символу S[i] в таблице поиска. Таким образом, сдвиг выполняется так, чтобы символы на соответствующих позициях в строке и слове совпадали. Чаще всего сдвиг выполняется на количество позиций больше 1.
Если символ строки поиска S[i] не встречается внутри слова P (хотя может быть последним символом слова P), то образ P сразу сдвигается вправо относительно строки поиска S на всю свою длину.
Пример. Пусть задана строка S:
высокопроизводительная система обработки информации
В этой строке необходимо найти слово P:
обработки
Тогда процесс поиска будет иметь вид:
высокопроизводительная система обработки информации
обработки
Несовпадение в строке S по символу о и сдвиг на 3 позиции так, чтобы символы на соответствующих позициях в строке и слове совпадали.
обработки
Несовпадение в строке S по символу в и, так как символ в не входит в слово, то сдвиг на всю длину слова.
обработки
Несовпадение в строке S по символу а и сдвиг на 5 позиций так, чтобы символы на соответствующих позициях в строке и слове совпадали.
обработки
Несовпадение в строке S по символу с и сдвиг на всю длину строки и, так как символ с не входит в слово, то сдвиг на всю длину слова.
обработки
Несовпадение в строке S по символу а и сдвиг на 5 позиций так, чтобы символы на соответствующих позициях в строке и слове совпадали.
обработки
Обнаружено вхождение слова P в строку S.
Приведенный выше алгоритм работает хорошо независимо от длины слова (подстроки) поиска и типа строки поиска. Так в рассматриваемом примере общее количество сравнений составило 14 = 5 + 9. Из них 5 – количество сравнений до начала совпадения с образом и 9 – количество сравнений, определяемых длиной образа.
Примечание. Вместо предложенной сложной схемы сдвигов можно применять и более упрощенную схему. При возникшем рассогласовании S[i] <> P[j] сдвиг образа P выполняется до первого с конца символа в образе, который совпадает с символом строки S[i], по которому произошло рассогласование. Если символ строки S[i], по которому произошло рассогласование, не входит в образ, то сдвиг выполняется на всю длину образа.
Ниже приводится программа, реализующая алгоритм Боуера-Мура, выполняющего сдвиг образа P вправо относительно строки поиска S на количество позиций, соответствующих в таблице поиска символу P[j], для которого произошло несовпадение, или на длину всего образа (слова), если символ S[i] не входит в состав искомого образа.
Таблица поиска реализуется в виде одномерного массива Shift, который содержит 256, элементов, пронумерованных в диапазоне от 0 до 255. Таким образом, порядковый номер элемента массива соответствует порядковому номеру соответствующего символа в кодовой таблице. Для каждого, кроме последнего, символа искомого слова в соответствующие позиции массива Shift заносится расстояние от последнего вхождения этого символа в искомое слово до конца слова, а для всех остальных символов массива Shift – длина искомого слова.
Ниже приводится процедура поиска подстроки в строке методом Боуера-Мура (БМ). Процедура в качестве параметров получает исходную строку Strng и образ поиска Pattern, а возвращает позицию Position в исходной строке, начиная с которой выполняется посимвольное совпадение элементов этой строки и элементов образа, а также признак успешности поиска Find.
procedure BMSearchSubString (const Strng: string; const Pattern: string;
var Position: integer; var Find: Boolean);
var J: integer;
LengthStr: integer; {длина строки поиска}
LengthPat: integer; {длина образа поиска}
StartComp: integer; {позиция начала сравнения – позиция текущего базирования конца образа в строке поиска}
CmpChrStr: integer; {позиция символа, подвергаемого сравнению, в строке поиска}
CmpChrPat: integer; {позиция символа, подвергаемого сравнению, в образе поиска}
Ch: char;
Shift: array [0..255] of integer; {таблица, которая для каждого символа, входящего в образ, содержит расстояние от его самого правого вхождения в образ до конца образа. Используется для определения количества позиций в строке поиска, на которые необходимо сдвинуть образ поиска вправо при частичном несовпадении образа поиска с фрагментом строки поиска}
begin
LengthStr := Length (Strng);
LengthPtr := Length (Pattern);
Find := false;
{подготовка массива Shift}
for J := 0 to 255 do Shift[J] := LengthPat; {В каждый элемент массива заносится длина искомого образа}
{корректировка массива Shift с первого по предпоследний символы искомого образа}
for J := 0 to LengthPat - 2 do Shift[Ord(Pattern[J])] := LengthPat – J - 1;
{Для каждого символа, входящего в образ (кроме последнего), в массиве Shift задается расстояние от его текущего вхождения в образ до конца образа. В результате для каждого такого символа, получим расстояние от его самого правого вхождения в образ до конца образа}
StartComp := LengthPat;
J := 0;
repeat
{начало очередного сравнения с образом поиска}
CmpChrPat := LengthPat;
CmpChrStr := StartComp;
repeat
CmpChrStr := CmpChrStr - 1;
CmpChrPat := CmpChrPat - 1;
until (CmpChrPat < 0) or (Pattern[CmpChrPat] <> Strng[CmpChrStr]);
{Сравнение выполняется до тех пор, пока не произойдет совпадение образа поиска и подстроки в строке поиска (первое условие) или пока не произойдет несовпадение очередных сравниваемых символов в строке и образе поиска (второе условие)}
{Сдвиг позиции начала сравнения в строке поиска}
StartComp := StartComp + Shift[Ord(Strng[CmpChrStr])]; {Сдвиг на количество позиций, соответствующих символу Strng[CmpChrStr] в таблице поиска или сдвиг на длину всего образа}
{ StartComp := StartComp + Shift[Ord(Strng[StartComp-1])]; Сдвиг до первого с конца символа в образе поиска, который совпадает с Strng[StartComp-1], или сдвиг на длину всего образа}
until (CmpChrPat < 0) or (StartComp > LengthStr); {Сравнение выполняется до тех пор, пока не произойдет совпадение образа поиска и подстроки в строке поиска или пока не исчерпается строка поиска}
if CmpChrPat < 0 then Find := true;
end; {BMSearchSubString}
Далее приводится текст программы, которая реализует ввод с терминала исходной строки и образа и размещает их в соответствующих массивах типа char, осуществляет поиск вхождения образа в строку методом Боуэра-Мура и одновременно выводит на экран уже рассмотренный фрагмент строки, что позволяет проиллюстрировать процесс поиска, как показано в приводимом выше примере.
program SearchSubString; {алгоритм Боуера-Мура (БМ)}
uses Crt;
const NMax = 1000;
MMax = 100;
type TFile = Text;
var J: integer;
LengthStr: integer; {длина строки поиска}
LengthPat: integer; {длина образа поиска}
StartComp: integer; {позиция начала сравнения – позиция текущего базирования конца образа в строке поиска}
CmpChrStr: integer; {позиция символа, подвергаемого сравнению, в строке поиска}
CmpChrPat: integer; {позиция символа, подвергаемого сравнению, в образе поиска}
Ch: char;
Strng: array [0..NMax-1] of char; {строка поиска}
Pattern: array [0..MMax-1] of char; {образ поиска}
Shift: array [0..255] of integer; {таблица, смещений}
FileName: string;
Fi: TFile; {Ввод с клавиатуры как из файла произвольной длины}
begin
Clrscr;
WriteLn;
WriteLn ('Ввод строки поиска: ');
WriteLn ('Для завершения ввода строки поиска нажмите клавишу CTRL+Z');
WriteLn;
FileName := 'Con';
Assign (Fi, FileName);
Reset (Fi);
{ввод строки поиска}
LengthStr := 0;
while not EOF (Fi) do
begin
Read (Fi, Ch);
Strng[LengthStr] := Ch;
LengthStr := LengthStr+1;
end;
WriteLn;
{поочередный ввод одного или нескольких образов поиска}
while true do
begin
WriteLn ('Ввод очередного образа поиска (подстроки): ');
WriteLn ('Для завершения ввода образа поиска (подстроки) нажмите клавишу CTRL+Z');
WriteLn;
FileName := 'Con';
Assign (Fi, FileName);
Reset (Fi);
{Ввод очередного образа поиска}
LengthPat := 0;
while not EOF (Fi) do
begin
Read (Fi, Ch);
Pattern[LengthPat] := Ch;
LengthPat := LengthPat + 1;
end;
{подготовка массива Shift}
for J := 0 to 255 do
Shift[J] := LengthPat; {В каждый элемент массива заносится длина искомого образа}
{корректировка массива Shift с первого по предпоследний символы искомого образа}
for J := 0 to LengthPat - 2 do
Shift[Ord(Pattern[J])] := LengthPat – J - 1;
StartComp := LengthPat;
J := 0;
repeat
while J < StartComp do {Последовательно выводятся очередные части строки до позиции StartComp - начала очередного сравнения с образом поиска}
begin
Write (Strng[J]);
J := J + 1;
end;
{начало очередного сравнения с образом поиска}
CmpChrPat := LengthPat;
CmpChrStr := StartComp;
repeat
CmpChrStr := CmpChrStr - 1;
CmpChrPat := CmpChrPat - 1;
until (CmpChrPat < 0) or (Pattern[CmpChrPat] <> Strng[CmpChrStr]);
{Сдвиг позиции начала сравнения в строке поиска}
StartComp := StartComp + Shift[Ord(Strng[CmpChrStr])];
until (CmpChrPat < 0) or (StartComp > LengthStr);
if CmpChrPat < 0
then WriteLn ('!! ОБРАЗ НАЙДЕН !!')
else
begin
while J <= LengthStr - 1 do {Выводится остаток строки поиска т.к. позиция StartComp вышла за пределы строки}
begin
Write (Strng[J]);
J := J+1;
end;
WriteLn ('?? ОБРАЗ НЕ НАЙДЕН ??');
end;
WriteLn;
WriteLn ('Для завершения поиска нажмите клавишу Esc, иначе другую клавишу');
if ReadKey = Char(27) then Exit;
end;
end.