- •Алгоритмы и алгоритмические языки
- •Лекция 1
- •Представление чисел в эвм
- •Вещественные
- •Ошибки вычислений
- •Лекция 2
- •Алгоритмы. Сведение алгоритмов.
- •Нижние и верхние оценки.
- •Сортировки
- •Постановка задачи
- •Сортировка пузырьком.
- •Сортировка слиянием с рекурсией.
- •Сортировка слиянием без рекурсии.
- •Лекция 3
- •Алгоритмы. Сведение алгоритмов.
- •Сортировки и связанные с ними задачи.
- •Доказательство корректности работы алгоритма.
- •Оценки времени работы алгоритма.
- •Некоторые задачи, сводящиеся к сортировке.
- •Лекция 4
- •Алгоритмы. Сведение алгоритмов.
- •Сортировки и связанные с ними задачи.
- •HeapSort или сортировка с помощью пирамиды.
- •Алгоритмы сортировки за время o(n)
- •Сортировка подсчетом
- •Цифровая сортировка
- •Сортировка вычерпыванием
- •Лекция 5
- •Алгоритмы. Сведение алгоритмов.
- •Порядковые статистики.
- •Поиск порядковой статистики за время (n) в среднем
- •Поиск порядковой статистики за время (n) в худшем случае
- •Язык программирования c.
- •Переменные
- •Структуры данных.
- •Вектор.
- •Лекция 6
- •Стек. Реализация 1 (на основе массива).
- •Стек. Реализация 2 (на основе массива с использованием общей структуры).
- •Стек. Реализация 3 (на основе указателей).
- •Стек. Реализация 4 (на основе массива из двух указателей).
- •Стек. Реализация 5 (на основе указателя на указатель).
- •Очередь.
- •Стандартная ссылочная реализация списков
- •Ссылочная реализация списков с фиктивным элементом
- •Реализация l2-списка на основе двух стеков
- •Реализация l2-списка с обеспечением выделения/освобождения памяти
- •Лекция 7
- •Структуры данных. Графы.
- •Поиск пути в графе с наименьшим количеством промежуточных вершин
- •Представление графа в памяти эвм
- •Массив ребер
- •Матрица смежности
- •Матрица инцидентности
- •Списки смежных вершин
- •Реберный список с двойными связями (рсдс) (для плоской укладки планарных графов)
- •Лекция 8
- •Структуры данных. Графы.
- •Поиск кратчайшего пути в графе
- •Алгоритм Дейкстры
- •Конец вечного цикла
- •Алгоритм Дейкстры модифицированный
- •Конец вечного цикла
- •Лекция 9
- •Бинарные деревья поиска
- •Поиск элемента в дереве
- •Добавление элемента в дерево
- •Поиск минимального и максимального элемента в дереве
- •Удаление элемента из дерева
- •Поиск следующего/предыдущего элемента в дереве
- •Слияние двух деревьев
- •Разбиение дерева по разбивающему элементу
- •Сбалансированные и идеально сбалансированные бинарные деревья поиска
- •Операции с идеально сбалансированным деревом
- •Операции со сбалансированным деревом
- •Поиск элемента в дереве
- •Добавление элемента в дерево
- •Удаление элемента из дерева
- •Поиск минимального и максимального элемента в дереве
- •Поиск следующего/предыдущего элемента в дереве
- •Слияние двух деревьев
- •Разбиение дерева по разбивающему элементу
- •Лекция 10
- •Красно-черные деревья
- •Отступление на тему языка с. Поля структур.
- •Отступление на тему языка с. Бинарные операции.
- •Высота красно-черного дерева
- •Добавление элемента в красно-черное дерево
- •Однопроходное добавление элемента в красно-черное дерево
- •Удаление элемента из красно-черного дерева
- •Лекция 11
- •Высота b-дерева
- •Поиск вершины в b-дереве
- •Отступление на тему языка с. Быстрый поиск и сортировка в языке с
- •Добавление вершины в b-дерево
- •Удаление вершины из b-дерева
- •Лекция 12
- •Хеширование
- •Метод многих списков
- •Метод линейных проб
- •Метод цепочек
- •Лекция 14
- •Поиск строк
- •Отступление на тему языка с. Ввод-вывод строк из файла
- •Алгоритм поиска подстроки с использованием хеш-функции (Алгоритм Рабина-Карпа)
- •Конечные автоматы
- •Отступление на тему языка с. Работа со строками
- •Алгоритм поиска подстроки, основанный на конечных автоматах
- •Лекция 15
- •Алгоритм поиска подстроки Кнута-Морриса-Пратта (на основе префикс-функции)
- •Алгоритм поиска подстроки Бойера-Мура (на основе стоп-символов/безопасных суффиксов)
- •Эвристика стоп-символа
- •Эвристика безопасного суффикса
- •Форматы bmp и rle
- •Bmp без сжатия.
-
Алгоритм поиска подстроки Бойера-Мура (на основе стоп-символов/безопасных суффиксов)
Алгоритм напоминает элементарный алгоритм поиска подстроки в строке. Основное отличие – сравнение искомой строки W с соответствующей частью строки S осуществляется не слева направо, а справа налево. По результатам сравнения делается вывод – на сколько можно сместиться вправо для сравнения W со следующей подстрокой S (в элементарном алгоритме поиска сдвиг всегда происходит на одну позицию). При этом, есть два независимых алгоритма, позволяющих вычислять, на сколько можно смещаться вправо для сравнения со следующей подстрокой S. Выбирается максимальный из сдвигов, получаемых по этим алгоритмам. Рассмотрим эти два алгоритма.
-
Эвристика стоп-символа
Рассмотрим несколько примеров.
Пример 1. S=”ababababa”, W=”cccc”.
Сначала сравниваем суффикс S4 и W (S4 - подстрока S,состоящая из ее первых четырех символов). Как уже отмечалось, сначала сравниваем S[3] и W[3]. Они не равны, следовательно, S4 и W не равны. Более того, т.к. S[3] вообще не встречается в W, то далее можно сравнивать с W уже S4+strlen(W)=S8, т.к. суффиксы S4+1,…, S4+strlen(W)-1 заведомо не совпадают с W.
Пример 2. S=”ababacaba”, W=”abac”.
Сначала сравниваем суффикс S4 и W. Как уже отмечалось, сначала сравниваем S[3] и W[3]. Они не равны, следовательно, S4 и W не равны. S[3] встречается первый раз в W (при просмотре с конца) в позиции 1, то далее можно сравнивать с W уже S4+strlen(W)-1-1=S6, т.к. при таком сдвиге впервые S[3] совпадет с соответствующим символом W.
Вообще говоря, пусть сравнивается суффикс Sk и W. Пусть W[l] – первый справа символ W, не совпавший с соответствующим символом строки S, т.е.
S[k-strlen(W)+l]!=W[l], S[k-strlen(W)+i]==W[i] (strlen(W)>i>l).
Если l==0, то мы нашли вхождение W в S. Переходим к анализу Sk+1.
Рассмотрим случай l>0. Обозначим s= S[k-strlen(W)+l] .
Пусть m(s) – функция, выдающая самое правое вхождение символа s в строку W. В случае, если символ s в строке W не найден, пусть m(s)=-1. Тогда, следующим претендентом на сравнение будет Sk+MAX(1,strlen(W)-1-m(s)).
Здесь и далее MAX и MIN в языке С можно определить следующим образом
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
Функция m является табличной, поэтому ее можно заменить соответствующим массивом. Например, если мы производим поиск строк в языке С, то m можно определить следующим образом
unsigned char m[256];
Все значения массива изначально инициализируются значением -1. Далее для всех символов W[i] строки W от первого до последнего следует положить
m[W[i]]=MAX(m[W[i]],i);
На самом деле, с точки зрения языка С, последнее утверждение не верно!!! Это связано с тем, что переменная m[k] , вообще говоря, знаковая. Следующая попытка исправить ситуацию тоже не верна
m[(unsigned)W[i]]=MAX(m[(unsigned)W[i]],i);
Связано это с тем, что преобразование
signed char -> unsigned int
происходит, на самом деле, более сложно:
signed char -> signed int -> unsigned int
в результате получаем, что отрицательное 8-битное число преобразуется, сначала, в отрицательное 32-битное число, а только потом произойдет преобразование к беззнаковому числу. Итого
’а’=-32 -> 4294967264
Правильное преобразование показано в следующей функции, вычисляющей массив m
void MakeM(char W[], int l, int m[256])
{int i;
for(i=0;i<256;i++)m[i]=-1;
for(i=0;i<l;i++)m[(unsigned char)W[i]]=MAX(m[(unsigned char)W[i]],i);
}
Осталось написать подпрограмму, осуществляющую поиск первого вхождения строки W длины lW в строку S длины lS
char *Search(char S[], int lS, char W[], int lW, int m[256])
{int l,k; if(lS<lW)return NULL;
for(k=lW;k<=lS;k=k+MAX(1,strlen(W)-1-m[(unsigned char)W[l]]))
{
for(l=lW-1;l>=0;l--)if(W[l]!=S[k-lW+l])break;
if(l<0)return S+k-lW;
}
return NULL;
}