Костюк - Основы программирования
.pdf101
Иногда контекстный поиск можно выполнить гораздо быстрее. Пусть, например, текст содержит предложения на русском языке, и образцом является слово русского языка. Тогда совпадение может начинаться с такой буквы, которая является самой первой в тексте либо стоит после пробела или знака препинания.
В этом случае в алгоритме поиска можно вначале выделить очередное слово в тексте, а затем сравнить его с образцом.
Пример 5.6. Поиск слова d в символьном массиве S длиной n. Слова разде ляются пробелами и другими символами, не являющимися буквами или цифрами. Ре зультат: i – номер символа S[i], совпадающего с первой буквой слова. Если пол ного совпадения нет, то i=0.
|
|
m:=length(d); p:=0; j:=1; |
|
while (p<2)and(j<=n-m+1) do |
|
begin c:=S[j]; |
|
if p=0 then begin |
|
if Y[ord(c)]=1 then |
|
end begin d1:=c; p:=1; i:=j end |
|
else begin |
(5.17) |
if Y[ord(c)]=1 then d1:=d1+c |
|
else if scomp(d,d1)=0 then p:=2 |
|
else p:=0 |
|
end; |
|
j:=j+1 |
|
end; |
|
if p=0 then i:=0 |
|
else if (p=1)and(scomp(d,d1)<>0) then i:=0; |
|
Для определения вида символа используется вспомогательный массив Y с опи
санием, аналогичным таблице T (5.14). Элемент Y[i]=1, если символ с кодом i является буквой, и Y[i]=0, если символ с кодом i не является буквой.
Переменная p в алгоритме имеет смысл состояния процесса распознавания. Если p=0, то еще не начато выделение очередного слова, т.е. перед этим были обна ружены символы-разделители. Если p=1, то начато выделение слова и его началь ные символы помещены в переменную d1. Наконец, если полное выделенное слово совпало с образцом, то p=2 и цикл прекращается. Сравнение с образцом осуще ствляется функцией scomp. Дополнительное сравнение с образцом после цикла необходимо из-за того, что искомое слово может находиться в самом конце текста без последующего разделителя.
Алгоритм имеет трудоемкость порядка n. Действительно, основной цикл испол няется не более n раз. Внутри цикла обычно производится не более двух сравнений, и только в случае полного выделения очередного слова длиной l, на что предвари тельно потребуется l шагов основного цикла, будет выполняться сравнение с образ
102
цом, на которое будет затрачено не более l шагов (в функции scomp). Таким об разом, количество шагов выделения очередного слова и его сравнения с образцом не больше, чем удвоенная длина этого слова.
Конец примера.
Пример 5.7. Распознавание группы слов в символьном массиве S длиной n. Слова-образцы записаны в массиве строк D, их количество – k.
p:=0; j:=0; while j<=n do
begin j:=j+1;
{проверка для последнего слова без разделителя в конце:} if j<=n then c:=S[j] else c:=' ';
if p=0 then begin
if Y[ord(c)]=1 then begin d1:=c; p:=1; i:=j
end end
else begin
if Y[ord(c)]=1 then d1:=d1+c (5.18)
else begin {слово выделено, поиск совпадения} l:=1; p:=0;
while l<=k do
if comp(d1,D[l])=0 then begin r:=k+1;
writeln(D[l],i) end end
end end;
Информация о каждом распознанном слове выводится в виде: 1) распознанное слово; 2) номер символа в тексте, с которого начинается слово.
В алгоритме сравнение по группе образцов производится последовательно, поэтому трудоемкость алгоритма в наихудшем имеет порядок n ∙ k, где k – количе
ство слов-образцов. Трудоемкость можно уменьшить до |
nélog kù , применив ди |
хотомический поиск выделенного слова в предварительно |
упорядоченном массиве |
слов-образцов. |
|
Конец примера. |
|
5.3 Информационные таблицы
103
Объект, как элемент множества, можно задать в виде записи (структуры) зна чений характеристик, которые могут быть различных типов (числовыми, символьны ми строками и др.). Такие характеристики называют полями или ключами. Множе ство объектов при этом задается в виде информационной таблицы, каждый столбец в которой определяет поле, а каждая строка является записью. В программе инфор мационную таблицу можно представить различными способами:
1)в виде набора массивов (для каждого поля используется отдельный массив);
2)в виде массива записей;
3)в виде списка записей.
Пусть, например, таблица T содержит поля A, B, C, различающиеся по типам данных. Тогда i–я запись в информационной таблице может представляться:
1)совокупностью элементов массивов {A[i], B[i], C[i]};
2)элементом массива записей T[i] с полями:
{T[i].A, T[i].B, T[i].C}; 3) элементом списка записей с полями {A, B, C}.
Над множеством записей информационной таблицы можно выполнять различ ные действия, например, производить какие-либо вычисления. Часто в вычислениях должны участвовать не все записи, а лишь некоторые, удовлетворяющие какомулибо условию. Чтобы отобрать такие записи, выполняют поиск, аналогично тому, по иску в числовом или строковом массиве. При этом поиск может выполняться как по одному из полей, так и по нескольким различным полям.
Для ускорения многократного поиска по одному и тому же полю (при представ лении таблицы массивами) записи можно предварительно упорядочить по этому по лю. При необходимости поиска по различным полям создаются дополнительные ин дексные массивы, и выполняется косвенное упорядочение по каждому полю в отдельности.
Пример 5.8. Задача "спортивное двоеборье". Результаты соревнований спортсме нов по двум видам сведены в следующую таблицу:
Фамилия |
Результат по 1-му виду |
Результат по 2-му виду |
Требуется определить места, занятые спортсменами в двоеборье, по сумме мест в отдельных видах. Победитель определяется по минимальной сумме мест.
Пусть правила определения мест в двоеборье следующие:
1)если результаты по одному из видов у всех спортсменов различны, и эти ре зультаты упорядочить по возрастанию, то место по этому виду у спортсмена X рав но номеру спортсмена X в упорядоченном списке;
2)если результаты нескольких спортсменов по одному из видов одинаковы, то им следует приписать одинаковое среднее место по этому виду;
104
3) если у нескольких спортсменов сумма мест по обоим видам одинакова, то им следует приписать одинаковое среднее место по двоеборью.
Пусть входная таблица задана следующими массивами: F (Фамилия), R1 (Ре зультат по 1-му виду), R2 (Результат по 2-му виду). Количество записей в таблице задано в переменной n.
Для промежуточных вычислений зададим четыре дополнительных столбца во входной таблице:
Место по |
Место по |
Сумма мест по |
Общее место по |
1-му виду |
2-му виду |
двум видам |
двум видам |
Эти столбцы зададим следующими массивами: M1 (Место по 1-му виду), M2 (Место по 2-му виду), MS (Сумма мест по двум видам), M0 (Общее место по двум
видам). Кроме того, для косвенного упорядочения столбцов понадобится еще один целочисленный массив In (индексный). Пусть также все массивы (кроме F) в опи
сании имеют тип mas, с элементами типа real.
Вцелом алгоритм расчета мест будет следующим: place(R1,M1,n); {вычисление мест M1 по по 1-му виду}
place(R2,M2,n); |
{вычисление мест M2 по по 2-му виду} |
|
for i:=1 to n do |
{вычисление суммы мест M0} |
(5.19) |
MS[i]:=M1[i]+M2[i]; |
|
|
place(MS,M0,n); {вычисление мест M0 по по обоим видам} |
|
В алгоритме используется процедура place, вычисляющая места по одному ре зультату.
Алгоритм процедуры place в массиве M вычисляет места спортсменов по од ному из результатов, размещенных в массиве R:
|
|
|
|
|
procedure place(R,M:mas;n:integer); |
|
|
|
var i,ib,j:integer; |
|
|
|
begin |
|
|
|
ssort(R,In,n); |
|
|
|
{косвенная сортировка с индексным массивом In} |
|
|
|
for i:=1 to n do |
|
(5.20) |
|
if (i=n)or(R[In[i]]<>R[In[i+1]]) then |
|
|
|
begin |
|
|
|
for j:=ib to i do M[In[j]]:=(ib+b)/2; |
|
|
|
ib:=i |
|
|
|
end |
|
|
|
end; |
|
|
|
В алгоритме (5.20) используется процедура косвенной сортировки |
ssort, фор |
|
мирующая индексный массив In. |
|
|
105
Нетрудно видеть, что трудоемкость всего алгоритма определяется трудоемко стью используемого алгоритма сортировки, и может оцениваться как n log n .
Конец примера.
Особый интерес представляет случай, когда информация об объектах универсу ма рассеяна по нескольким таблицам. Такие таблицы можно соединять. Соединение двух таблиц производится по следующим правилам:
1)в каждой из входных таблиц определяется одно или несколько полей, которые однозначно определяют объекты универсума; такие поля, одинаковые для обеих та блиц, называют ключевыми;
2)выходная таблица содержит поля из обеих входных таблиц;
3)в случае, когда некоторый объект присутствует в виде записи в обеих входных таблицах, в выходной таблице для него формируется запись, содержащая значения из записей обеих входных таблиц;
4)в случае, когда некоторый объект присутствует в виде записи только в одной из входных таблиц, имеется четыре рассматриваемых ниже варианта формирования записи в выходной таблице.
Вариант 1. В выходной таблице соответствующая запись не формируется. Вариант 2. Если для некоторого объекта есть запись в 1-й таблице, но нет во 2-й,
то запись формируется, а если нет записи в 1-й таблице, то не формируется.
Вариант 3. Если для некоторого объекта есть запись во 2-й таблице, но нет в 1-й, то запись формируется, а если нет записи во 2-й таблице, то не формируется.
Вариант 4. Запись формируется, если для объекта есть запись хотя бы в одной из входных таблиц.
При формировании записи во втором-четвертом вариантах недостающие значе ния полей заполняются особым пропущенным значением.
Обозначим через A множество объектов, записи которых имеются в 1-й табли це, через B – множество объектов, записи которых имеются во 2-й таблице. Тогда в варианте 1 выходная таблица будет содержать записи пересечения множеств A ∩ B , в
варианте 2 – записи множества A, в варианте 3 – записи множества B, в варианте 4
– записи объединения множеств A U B .
Для эффективной реализации всех вариантов соединения, входные таблицы мож но предварительно упорядочить по совокупности ключевых полей. Тогда соединение можно выполнить с помощью модификации алгоритма слияния.
Пример 5.9. Формирование общей таблицы результатов по двум видам для зада чи "спортивное двоеборье".
Результаты соревнований спортсменов по двум видам записаны в две отдельные таблицы, каждая с двумя полями. Первая таблица содержит фамилию спортсмена (массив F1) и результат по 1-му виду (массив R01); Вторая таблица – фамилию спортсмена (массив F2) и результат по 2-му виду (массив R02). Количество запи сей в 1-й таблице – n1, во 2-й таблице – n2. Это соответствует тому, что некото рые спортсмены могли участвовать только в одном из видов двоеборья.
sort2(F1,R01,n1); |
{упорядочение 1-й входной таблицы} |
106
|
|
|
|
sort2(F2,R02,n2); |
{упорядочение 2-й входной таблицы} |
|
|
i1:=1; i2:=1; n:=0; |
{пересечение множеств} |
|
|
while (i1<=n1)and(i2<=n2) do |
(5.21) |
||
if F1[i1]<F2[i2] then i1:=i1+1 |
|||
|
|||
else if F1[i1]>F2[i2] then i2:=i2+1 |
|
||
else begin n:=n+1; |
|
|
|
F[n]:=F1[i1];R1[n]:=R01[i1];R2[n]:=R02[i1]; |
|
||
i2:=i2+1; i1:=i1+1 |
|
|
|
end; |
|
|
Соединение таблиц в алгоритме (5.21) реализуется по варианту 1 (пересечение множеств), т.е. спортсмены, участвовавшие только в одном из видов, не могут пре тендовать на победу в двоеборье.
Используемая в алгоритме процедура sort2 упорядочивает символьные стро ки массива, заданного как первый параметр, с одновременной перестановкой элемен тов числового массива – второго параметра. Третий параметр задает размеры масси вов.
Конец примера.
Вопросы и задания
1.Написать алгоритмы преобразования представления множества из двоичного массива в упорядоченный список и обратно.
2.Как выполняется проверка принадлежности объекта множеству при различных способах задания множества, и какова ее трудоемкость?
3.Как выполняется добавление объекта в множество при различных способах задания мно жества, и какова его трудоемкость?
4.Как выполняется удаление объекта из множества при различных способах задания множе ства, и какова его трудоемкость?
5.Как вычисляется мощность множества при различных способах задания множества, и с какой трудоемкостью?
6.Как вычисляются объединение, пересечение, разность и симметрическая разность мно жеств, заданных двоичными массивами, и с какой трудоемкостью?
7.Доказать правильность алгоритма (5.10), вычисляющего объединение множеств, заданных целочисленными упорядоченными массивами.
8.Доказать правильность алгоритма (5.11), вычисляющего пересечение множеств, заданных целочисленными упорядоченными массивами.
9.Написать алгоритмы вычисления разности и симметрической разности множеств, задан ных целочисленными упорядоченными массивами. Доказать их правильность.
10.Написать алгоритмы вычисления объединения, пересечения, разности и симметрической разности множеств, заданных целочисленными неупорядоченными массивами. Доказать правильность алгоритмов и определить их трудоемкость.
107
11.Доказать правильность алгоритма (5.12), вычисляющего объединение множеств, заданных упорядоченными списками.
12.Доказать правильность алгоритма (5.13), вычисляющего пересечение множеств, заданных упорядоченными списками.
13.Написать алгоритмы вычисления разности и симметрической разности множеств, задан ных упорядоченными списками. Доказать правильность алгоритмов.
14.Что означает лексикографический порядок символьных строк?
15.Для чего в алгоритме (5.15), выполняющем лексикографическое сравнение двух символь
ных строк, используется таблица перекодировки? Доказать правильность алгорит ма (5.15).
16.Написать алгоритм лексикографического упорядочения массива символьных строк с ис пользованием таблицы перекодировки, взяв за основу какой-либо простой алгоритм сор тировки.
17.Используя алгоритм контекстного поиска (5.16), написать и отладить программу, которая вводит две символьные строки и выполняет поиск первой строка внутри второй, как подстроки, с отождествлением заглавных и строчных букв.
18.Используя алгоритм распознавания слов (5.18), написать и отладить программу, которая вводит массив символов (текст), выделяет в нем слова, состоящие только из букв (с отож дествлением заглавных и строчных букв) и формирует словарь из этих слов, как массив строк. В словаре все слова должны быть различными.
19.Используя алгоритмы (5.19), (5.20) и (5.21), написать и отладить программу, которая пол ностью решает задачу "спортивное двоеборье": вводит таблицу результатов спортсменов в отдельных видах, после чего вычисляет и выводит места спортсменов по сумме мест в двух видах соревнований.
Глава 6 Алгоритмы с графами и отношениями
6.1 Представление графов и отношений
Граф задается двумя множествами: множеством вершин и множеством ребер (дуг). Ребро (дуга) задается парой вершин (которые оно соединяет). Имеются различ ные виды графов:
1)неориентированные графы, в таких графах для ребер не важен порядок зада ния вершин в паре, если вершина i соединена ребром с вершиной j, то это то же самое, что вершина j соединена ребром с вершиной i;
2)ориентированные или орграфы, в таких графах дуга определяет порядок зада
ния вершин в паре, если есть дуга из вершины i в вершину j, то дуга из вершины j
ввершину i может существовать, а может и не существовать;
3)взвешенные графы, в которых каждому ребру (дуге) приписывается вес, та кие графы могут быть как ориентированными, так и неориентированными.
Кроме того, в мультиграфе одну и ту же пару вершин могут соединять несколь ко различных ребер (дуг).
Отношение на конечном множестве можно представить в виде ориентированного графа, поэтому задачи для отношений можно переформулировать в виде задач для орграфов.
Представление графа списком ребер (дуг). Для задания множества вершин гра фа достаточно указать их количество, предполагая, что вершины перенумерованы на туральными числами 1, 2, …, n. В ориентированном графе дуги или в неориентиро ванном графе ребра можно задать списком (массивом) пар вершин, причем для ори ентированного графа важен порядок задания вершин в каждой из пар. Если граф взвешен, то дополнительно с каждой парой вершин задают вес ребра (дуги). Этот способ обычно используется для хранения информации о графе, в то же время он не слишком эффективен для использования в алгоритмах, в которых приходится много кратно просматривать ребра.
Представление графа матрицей смежности. Ребра (дуги) графа можно задать в виде квадратной матрицы смежности, элемент которой Mij = 1, если есть ребро, со единяющее вершины i и j (или дуга идущая из вершины i в j), и равен нулю в противном случае. Для неориентированного графа матрица смежности симметрична (Mij = Mji), так как каждое ребро представлено двумя элементами матрицы. Во взве
109
шенном графе элемент матрицы равен весу ребра (дуги) или особому значению (бес конечности), если между соответствующими вершинами нет ребра (дуги).
Чтобы просмотреть все вершины, смежные по ребрам с вершиной i (или вер шины, в которые идут дуги из i), необходимо перебрать элементы i –й строки мат рицы. Для просмотра вершин, из которых идут дуги в вершину i, необходимо пере брать элементы i –го столбца матрицы.
Представление графа списками смежных вершин. Если число ребер графа с большим числом вершин n существенно меньше, чем n2, то в матрице смежности большинство элементов будут нулевыми, и трудоемкость алгоритмов, просматрива ющих все ребра, будет намного больше минимально возможной. Так, например, для плоского графа число ребер меньше, чем 3∙n, однако трудоемкость просмотра всех ребер по матрице смежности будет порядка n2.
В этом случае более эффективно представление графа в виде массива из n ука зателей и n списков вершин, таких, что i-й указатель ссылается на тот список, кото рый содержит номера вершин, смежных с i-й вершиной. На рис. 6.1 изображен при мер неориентированного графа и его представление списком ребер, матрицей смеж ности и списками смежных вершин.
|
1 |
|
|
(1,2) |
1 |
1 |
2 |
3 |
4 |
5 |
6 |
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
(3,1) |
|
1 |
1 |
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
3 |
|
|
|
|
|
|||
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(2,3) |
|
|
|
|
|
|
|
|
|
|
|
1 |
|
|
|
|
3 |
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
|
3 |
1 |
1 |
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(4,3) |
|
|
|
|
|
|
|
|
|
|
1 |
|
|
|
|
2 |
|
|
|
|
4 |
|||||
|
|
|
|
|
4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
6 |
|
(5,6) |
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
5 |
|
|
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
|
|
|
|
|
|
|
|
|
||
|
7 |
|
|
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Рис. 6.1
В представлении графа списками смежных вершин указатели в массиве можно описать типом pel, как в алгоритме (3.21). Такое представление подходит как для
ориентированного, так и для неориентированного графа. Если граф взвешенный, то в каждом из элементов списка необходимо в отдельном поле хранить вес соответству ющего ребра (дуги).
Чтобы просмотреть все вершины, смежные по ребрам с вершиной i (или вер шины, в которые идут дуги из i), необходимо перебрать все элементы i–го списка. Однако для просмотра вершин, из которых идут дуги в вершину i, необ ходимо перебрать все элементы во всех списках.
Каждый из списков является множеством смежных вершин. Алгоритмы поиска (5.2), вставки (5.3) и удаления (5.4) элементов для него описаны в разделе 5.1 для случая, когда списки упорядочены. При неупорядоченности списков просмотр в этих алгоритмах будет требовать в среднем вдвое больше шагов.
110
Рассмотрим формирование списков, задающих граф.
Пример 6.1. Пусть совокупность m ребер (дуг) графа из n вершин задана c по мощью массивов v1 и v2 следующим образом: в элементах v1[i], v2[i] запи саны номера вершин, соединенных между собой i–м ребром, i=1, …, m. Массив S
содержит n элементов, имеющих тип pel, |
которые будут указателями на списки. |
|||
Вспомогательная переменная ps также имеет тип pel. |
|
|||
|
for k:=1 to n |
do S[k]:=nil; |
{обнуление указателей} |
|
|
for i:=1 to m |
do |
{формирование списков} |
|
|
begin new(ps); ps^.s:=v2[i]; |
|
||
|
k:=v1[i]; |
ps^.p:=S[k]; S[k]:=ps; |
(6.1) |
|
|
{формирование 2-го элемента для неориентированного графа:} |
|
||
|
new(ps); ps^.s:=v1[i]; |
|
|
|
|
k:=v2[i]; |
ps^.p:=S[k]; S[k]:=ps |
|
|
|
end; |
|
|
|
В алгоритме (6.1) вначале обнуляются указатели в массиве S. Затем формиру ются списки номеров смежных вершин. Для неориентированного графа формируется по два элемента списка на каждое ребро, а для ориентированного – один элемент на каждую дугу. Трудоемкость обоих этапов алгоритма – линейная от числа вершин или ребер графа.
Если списки требуется упорядочить, то при заполнении списков необходимо в целочисленном массиве L подсчитывать их длины, а затем дополнительным этапом
каждый из списков отсортировать по отдельности, используя, например, алгоритм (4.7).
Конец примера.
Представление графа массивом смежных вершин. Если списки номеров смежных вершин разместить подряд в общем для всех списков массиве, получим структуру, изображенную на рис. 6.2. Здесь все списки размещены в целочисленном массиве D, размер которого для неориентированного графа равен удвоенному числу
ребер, а для ориентированного – числу ребер. Эти списки могут быть упорядоченны ми для ускорения в них поиска. В массиве S размещены для каждого из списков ин дексы начала, а в массиве L – длины списков. Длина массивов S и L равна коли
честву вершин графа. Если граф взвешенный, то необходим еще один массив (такой же длины, что и массив D) с весами ребер.