Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

алгоритмы1

.pdf
Скачиваний:
9
Добавлен:
10.06.2015
Размер:
1.34 Mб
Скачать

В соответствии с так определенной структурой 2-3 дерево имеющее k-уровней будет иметь от 2k-1 до 3k-1 листьев. Дерево в котором хранится n элементов будет иметь не более 1+ log3(n) и не менее 1+log2(n) уравнений, а значит длины от корня к листу будут иметь в худшем случае O(log3(n)).

Поиск записи с ключом x будет осуществляться за время порядка O(log2(n)), т.к при поиске нам придется переместиться от корня до листа.

Причем будет осуществляться:

Обозначим через y и z значения ключей в промежуточном узле (node). В качестве node можно рассмотреть корень

Тогда если x < y мы перемещаемся к 1-му сыну узла node

Если x y и у узла node 2 сына, то перемещаемся ко 2-мы сыну

Если у узла node 3 сына и x z, то перемещаемся к 3-му сыну, иначе ко 2-му

При достижении листа сравниваем x c ключом x` хранящимся в этом узле, и если x = x`, то элемент найден, а иначе констатируем отсутствие элемента в хранилище.

40.Вставка элемента в 2-3 дерево.

Начинается процесс так же как и процесс поиска, если поиск показывает, что элемент уже есть, то работа прекращается, иначе должны добавить.

Пусть в процессе поиска мы добрались до узла node, который предшествует листьям, если node имеет 2-х сыновей, то x делаем 3-м сыном, при этом новый лист располагается, так, чтобы все сыновья располагались слева на право, в порядке возрастания ключа.

Например при вставки элемента 18 в дерево 4.12 получим:

Рис. 4.13

В последнем промежутке ключь нужно менять.

Рассмотрим случай, когда x оказывается 4-м сыном листом некоторого промежуточного узла node. Пусть например в дерево на рисунке 4.13 x = 10. В этом случае на этапе поиска мы окажемся во

2-м узле 2-го уровня, у которого уже есть 3 сына, разбиваем его, один как node, а другой mode`. Два наименьших листа сыновья node, т.к node был разбит на 2, у его родителя p может оказаться 4 сына, тогда мы его тоже разбиваем. Если p-корень, то мы разобьем на 2 узла и образуем новый корень.

Рассмотрим пример вставки элемента 10 на рис. 4.13:

Рис. 4.14

*здесь сохраняем старые данные, т.к дерево придется перестроить

Корень имеет 4-х сыновей, поэтому разбиваем на 2 узла и строим новый корень.

Рис. 4.15

Пересчитаем промежуточные данные, если до поступления в хранилище в нем был 1-н элемент, то нужно сформировать дерево с корнем и 2-мя листьями. Все элементы на уровне листьев будут располагаться в порядке возрастания.

41.Удаление элемента из 2-3 дерева

Вначале ищем элемент x в дереве и после нахождения удаляем лист. Если удаляемый лист имеет 1-го брата, то получим узел node на предпоследнем уровне с 1-м сыном, что не допустимо. Если node – корень, то сын становится корнем. Пусть node – не корень. Родители node p. Если этот родитель имеет еще сына расположенного слева и пусть этот сын имеет 3-х сыновей, тогда старший по ключу становится сыном node.

Родитель p имеет еще сына справа от node имеющего 3-х сыновей, тогда младший по значению ключа становится сыном node.

Если эти варианты не реализуются, т.е другие сыновья имеют только 2х сыновей, то сын node становится сыном одного из братьев, а node удаляется.

Рассмотрим случайное удаление элемента 10 из рис. 4.15, получим:

Рис. 4.16

Обратим внимание, что в этом дереве содержаться также элементы, что и на рис. 4.13, но структуры разные. Причем иллюстрируя неоднозначность структуры при фиксированном наборе.

Пусть теперь необходимо удалить элемент 7 из дерева, после его удаления его родитель будет иметь 1-го сына – элемент 8 => этого сына нужно присоединить к 1-му из братьев родителя, а самого родителя удалить:

Рис. 4.17

В результате появится промежуточный узел с 1-м сыном, что не допустимо в 2-3 дереве. Поэтому данный узел удаляем, а единственного сына делаем сыном узла расположенным справа. Однако этот последний узел становится единственным сыном своего родителя, причем его родитель

– корень. Поэтому удаляем корень и получаем дерево такой структуры:

Рис. 4.18

42. Остовные деревья минимальной стоимости (ОДМС) – основные понятия. Основное свойство ОДМС (с доказательством).

Пусть задан неориентированный граф G (V, Х). Вещественно заданную функцию c(x), которая задана на множестве ребер Х будем называть стоимостью ребер. Остовным графом G называется свободное дерево, т.е дерево без корня, содержащее все вершины графа G и только эти вершины, и множество ребер которого является подмножеством множества X ребер графа G. Стоимость остовного дерева определяется как сумма стоимостей его ребер. Существенный интерес представляют остовные деревья минимальной стоимости (ОДМС).

Если учесть 2-е из этих свойств, то добавление в T ребра {u, v} приведет к образованию цикла, этот цикл будет содержать ребро {u, v} и еще какое-то ребро {u`, v`}, при этом u` U, v` V/U. Удалим ребро {u, v} => цикл будет разорван => образуем новое остовное дерево, стоимость которого будxет не больше стоимости дерева T, т.к стоимость {u, v} не может быть больше {u`, v`}. Таким образом мы приходим к противоречию со сделанным предположением:
x Либо ребро {u, v} принадлежит X` и T – ОДМС
Либо стоимость ребра {u, v} = стоимости ребра {u`, v`}, но тогда существует другое ОДМС T*, которому принадлежит ребро {u, v}
Либо T – не ОДМС, тогда все предположение не верно
43. Алгоритм Прима построения ОДМС.

На рис. 5.1 показан граф и его ОДМС.

Рис. 5.1

Одной из практических задач для которой могут быть полезны ОДМС является задача минимализации коммуникационной сети. В этой задачи вершиной обозначаются города, а линиями – коммуникационные сети. Требуется построить коммуникационную сеть, связывающую 2 города и имеющую минимальную стоимость.

Обозначим через U произвольное подмножество множества V вершин графов. Пусть {u, v} – это ребро наименьшей стоимости серди ребер у которых 1-я и 2-я вершины берутся из u U, v V/U, тогда существует ОДМС графа G содержащим ребро {u, v}.

Доказательство (метод от противного):

Предположим, что существует остовное дерево минимальной стоимости T=(V, X`) и такое ребро {u, v} наименьшей стоимости среди ребер у которых u U, v V/U и при этом {u, v} не принадлежит X` и не входит в состав другого ОДМС.

Любое дерево обладает следующими свойствами:

1.Дерево с n вершинами имеет (n-1) ребер

2.Если в дерево добавить новое ребро не увеличивая число вершин, то в графе появится цикл

В алгоритме последовательно строится множество вершин U, из которого пореберно вырастает остовное дерево. Пусть V={1, 2, 3, … , n}; U={1}. На каждом шаге находим {u, v} наименьшей стоимости, у которого u принадлежит U, v принадлежит V/U, после чего v переносится из множества V/U в множество U. Алгоритм завершается когда U=V.

Псевдокод алгоритма Прима:

procedure Prim (G: <граф>; T: <множество ребер дерева>);

var

U: < … >;

v, u: <выршины>;

begin

T:= ø;

U:= {1};

while U=V do begin

<нахождение ребра {u, v} среди ребер u принадлежит U; v принадлежит V/U>

T:=T пересекается(U) с {u, v};

U:=v пересекается с {v};

 

end;

end; // конец алгоритма Прима

 

Для реализации алгоритма множества введем 2 массива:

x

Rib_u-i элемент Rib_u-i [i] содержит вершины u принадлежит U соединен ребром с вершиной

 

i i принадлежит V/U соедин. ребром имеющим наименьшую стоимость у которой одна

 

вершина i зафиксирована, а i принадлежит V/U переменная

x

LowCost [i] содержит значение стоимости ребра {Rib_u-i, i}.

Заполним ячейки массива Rib_u-i и LowCost индексированными номерами тех вершин, которые на данном этапе находятся в множестве V/U. На каждом шаге алгоритм просматривает массив LowCost находящий наименьшие значение LowCost[k], k принадлежит V/U и соединен ребром с вершиной из множества U. Ребро (k, Rib_u-i[k]) выводится на печать, массивы Rib_u-i и LowCost корректируются с учетом перехода k в U. На вход алгоритму подается матрица стоимостей исходного графа. Если какое-то ребро отсутствует, то его длину обозначим как очень большое число, которое будем хранить в памяти как iтfinity.

Рассмотрим фрагмент кодов:

const n=10 Double0;

infinity = 1.0E + 300;

type

StoimRib_u-i = array [1..n, 1..n] of Double;

procedure Prim (C: StoimRib); //данная процедура последовательно определяет и распечатывает ребра ОДМС

var

LowCost: array [1..n] of Double;

Rib_u-i: array [1..n] of Double;

i, j, k: Integer;

min: Double;

begin // начальное запоминание LowCost, с учетом, что в начале в множество U входит только 1-я вершина

for i:=2 to n do begin

LowCost[i]:= c[1, i];

Rib_u-i[i]:=1;

end;

Далее идет последовательный поиск ребер ОДМС.

for i:=2 to n do begin

Далее идет поиск в V/U вершина k имеет инцидентное ребро заканчивающееся в множестве U, при условии, что ребро имеет наименьшую стоимость среди рассматриваемых:

min:= LowCost[i];

k:=2;

for j:=3 to n do

if LowCost[j] < min then begin

min:=LowCost[j];

k:=j;

end;

PRINT (Rib_u-i[k], k);

LowCost[k]:=infinity; //благодаря искусственному изменению величин k будет интерпретироваться, как добавленное к U.

for j:=2 to n do

if (c[k, j] < LowCost[j]) end

LowCost[j] < infinity >) then begin

LowCost[j]:=c[k, j];

Rib_u-i[j]:=k;

end;

end;

end; //конец алгоритма Прима

Работа алгоритма иллюстрируется на рис. 5.2, где строится ОДМС для графа изображенного на рис. 5.1(а)

Рис. 5.2

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

решения задачи коммивояжера.

Задача коммивояжера формулируется так: в приближенном алгоритме найти гамильтонов цикл имеющий минимальную стоимость. Возможно, что нет ни одного гамильтонова цикла.

Эта задача относится к классу дискретной математики. В таких задачах опред. решение наход. знач. алг., в котором некоторая целивая функция достигается минимум или максимумn F(z).

ООФ – множество всех гамильтоновых циклов

ОЗФ – множество чисел

Задача нахождения гамильтонова цикла является NP – полной, а значит является задачей коммивояжера, т.е для нее не существует или не найден полиномиальный алгоритм определения

оптимального решения => если задача имеет большую размерность, то перебор всех допустимых решений за приемлемое время не реализуется => необходим алгоритм, который дает приблизительное решение, но за приемлемое время.

Один из классов поиска оптимального решения принято называть жадным алгоритмом, т.к каждый такой алгоритм на каждом шаге на основе грубых представлений об оптимальности пытается:

1.Либо захватить больше или быстрее какого-то ресурса

2.Либо сохранить в резерве как можно больше ресурса

3.Либо как можно меньше нарастить значение целевой функции в задаче на минимализацию. В частности жадный алгоритм для задачи коммивояжера на каждом шаге ищет самое короткое из тех, которые можно включить в цикл.

Основные элементы для данной задачи сводятся к следующим правилам выбора очередного ребра при построении гамильтонова цикла:

1.Добавление ребра не должно приводить к появлению в маршруте к вершине со степенью 3

2.Добавление ребра не превращает строящийся маршрут в цикл не являющийся гамильтоновым

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

1такой цикл.

45.Задача коммивояжера для полного графа с неравенством треугольника.

Основные шаги алгоритма решения задачи. Утверждение 5.1 максимально погрешности алгоритма.

Пусть функция стоимости ребер в положительном графе удовлетворяет: в графе G=(V,X) для любых 3-х вершин u, v, w принадлежащие V выполняющих условие С(u, w) ≤ C(u, v) + C(v, w) (*) В частности это неравенство справедливо если вершина является точками, а стоимости = расстоянию между вершинами.

Можно показать, что и в этом случае задача остается NP – полной => поиск приближенного алгоритма актуален.

Мы рассмотрим приближенный алгоритм, основанный на использовании остовного дерева минимальной стоимости.

Шаги алгоритма:

1.Строим ОДМС, например с помощью алгоритма Прима

2.Выберем произвольную вершину в качестве корневой

3.Совершим полный обход всех вершин дерева. Такой обход начинается с корня и идет по всем ребрам «левой» ветви до листа, после возвращается по этой же ветви до вершины у которой

имеется более одного сына, от этой вершины продолжает движение по ребру ведущему ко 2- мы сыну и т.д. На всем пути переписываем все встречающиеся вершины, в том числе и повторяющиеся. (см. рис. 5.4)

4.Проходя получившийся список вершин вычеркнуть повторяющиеся вершины, кроме последнего повтора корня, измененный список и будет последовательностью вершин гамильтонова цикла, его примем в качестве приближенного задачи коммивояжера.

Полный обход на рис. 5.4 даст такую последовательность вершин: v1, v2, v3, v8, v2, v1, v4, v5, v6, v5, v7, v5, v7, v5, v4, v1 (**)

Вычеркнув повторы, получим: v1, v2,v3, v8, v4, v5, v6, v7, v1

Соответствующий гамильтонов цикл показан на рис. 5.5. Его стоимость = 19,74

Для сравнения на рис. 5.6 показан гамильтонов цикл являющийся точным решением задачи

14,75.

Данный алгоритм не дает однозначного решения, т.к во-первых ОДМС может быть не единственным, во-вторых порядок нахождения списка вершин может быть разным, например оптимальный гамильтонов цикл на рис. 5.6 можно было бы получить если последовательность (**) пройти в 2 этапа. Сначала слева на право до v3 включительно, а потом оставшуюся часть справа на лево.

Утверждение 5.1:

Алгоритм поиска приближенного решения в полном графе с неравенством треугольника. Решение задается с ошибкой не более чем в 2 раза по стоимости найденного гамильтонова цикла.

Доказательство:

Пусть Н* - минимальный гамильтонов цикл, Н – гамильтонов цикл, найденный при помощи приближенного алгоритма. Необходимо доказать, что стоимость Н не превышает 2-х стоимостей Н* (С(Н) ≤ 2С(Н*))

Если удалить из Н* любое ребро, то мы получим остовное дерево (не обязательно минимальное), стоимость этого дерева не будет превосходить С(Н*) тем более это будет верно для любого ОДМС, т.е для любого ОДМС справедливо:

С(Т) ≤ С(Н*)

Пусть мы совершили полный обход W дерева Т, в этом случае каждое ребро будет пройдено дважды, т.е С(W) ≤ 2C(W)

В следствии неравенства треугольника при удалении W любая вершина стоимость может только уменьшаться => С(Н) ≤ С(W) => C(H) ≤ 2C(H*)

Ч.Т.Д.