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

алгоритмы1

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

−1

( 1) 1

 

=0

 

i → n-i-1 результате вся правая часть выражения 4.1 примет вид:

 

 

 

 

P(n) ≤ 1+2/n^2

−1

(4.2)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Выполнится следующее=1 неравенство:

 

 

 

 

 

 

 

 

 

 

 

 

 

P(n)≤(1+4log2(n))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

n=1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Т.к P(1)=1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

n=2 тоже справедливо P(2)=2≤(1+4log22)=5.

 

 

 

 

 

=1

 

2/ ^2

=1

 

придем к соотношению

=1 4 log

 

 

=1

 

 

 

Предположим, что утверждение выполняется для всех i<n, тогда вместо P(i)в формулу

получим P(n)≤1+(2/n^2)

−1

 

∑ =1−1

log2

 

 

−1

 

 

=> 2/n^2 −1

 

 

 

2

 

 

 

. Учтем, что

 

 

 

 

 

P(n)≤2+(8/n^2)2

 

2

 

 

 

 

 

(4.3)

 

 

 

 

 

4.21

, то

Разобьем (4.3) на 2-ве суммы в т. i=[n/2], тогда в 1-й сумме слагаемые не будут превышать

i*log2(n/2), а во 2-й i*log2(n). В результате получим:

 

 

∑ =1

log2

2

 

= 2 +1

log2

 

 

P(n)≤2+(8/n^2)*(

/2

 

 

 

1

 

 

(4.4)

 

 

 

 

 

 

При любом четном n 1-я сумма из 4.4 не превышает величины

(n^2/8)*log2(n/2)=(n^2/8)*log2(n)-(n^2/8). 2-я сумма не будет превышать: (3*n^2/8)*log2(n) => по индукции получим нужное нам соотношение: P(n)≤2+(8/n^2((n^2/2)*log2(n))-(n^2/8)=1+4*log2(n) (4.5)

Т.о доказано, что в дереве двоичного поиска, которое получилось путем случайной вставки n элементов средняя длина пути от корня до любого лисьа по произвольному пути имеющем порядок О(log2(n)),

Более тонкий анализ позволяет указать, что в формуле 4.5 коэффициенты можно заменить на

1.4.

На основе полученного результата можем утверждать, что в среднем время выполнения проверки на принадлежность данного оператора к дереву будет иметь порядок O(log2(n)), аналогичный порядок будет иметь оператор INSERT, DELETE и DELETEMIN.

34. Частично упорядоченные деревья – основные понятия. Оператор удаления наиболее приоритетного элемента из частично упорядоченного двоичного дерева.

Мы рассмотрим частично упорядоченное дерево, как очереди с приоритетами. Очередь с приоритетами предполагает, что на множестве x € M элементов заданы функции приоритетов Р(х) ее

областью значений будет некоторое подмножество множества вещественных чисел. Далее будем полагать, что у x приоритет тем выше, чем больше Р(х).

Абстрактный тип данных предполагает, что модель множества заданная с оператором INSERT DELETEMIN (удаление элемента с наивысшим приоритетом) MAKENULL, построение элементов в очереди с приоритетами предполагается, что очередь очередного элемента осуществляется по наибольшему приоритету.

Такая дисциплина используется в ОС компьютера при распределении каких-то ресурсов между процессами.

Существует несколько реализаций АТД очереди с приоритетом.

Рассмотрим способ использования упорядоченного дерева. Эти деревья относятся к классу сбалансированных деревьев, это понятие не имеет строго однозначного определения, а качественно нужно понимать так: листья возможны только на самом нижнем или на предыдущем уровне, но не на более высоких.

Все уравнения, кроме нижнего заполняются полностью, тем более сбалансировано, чем оно ближе к полному дереву. Дополнительно мы будем предполагать, где некоторые листья отсутствуют могут располагаться только правее присутствующих. Далее мы будем рассматривать в качестве сбалансированной бинарной части упорядоченные деревья. Частично упорядоченное будет пониматься так: пусть в узлах охраняться элементы какого-то множества и на нем задана функция Р(х). Каждому узлу придается приоритет равный приоритету хранящемуся в узле x, и будем полагать, что приоритет узла V не ниже чем приоритет любого его сына.

Пример:

Рис. 4.7

Отдельные узлы могут иметь одинаковые приоритеты. Удаление наиболее приоритетного элемента из частично упорядоченного 2-го дерева. В начале проведем анализ приоритета (рис. 4.7)

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

Рис. 4.8

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

Рис. 4.9 (а)

Рис. 4.9 (б)

Всилу сбалансированности пути длинною 1+log2(n) продпроцесс прохождения элемента до конечного узла будет иметь порядок О(log2(n))

35.Оператор вставки элемента в частично упорядоченное дерево.

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

Пусть в дереве 4.7 нам нужно добавить элемент P(x)=4.

Рис. 4.10 (а)

Рис. 4.10 (б)

Рис. 4.10 (в)

Проведем более подробный анализ. По условию работы этого элемента возможны 2-ве ситуации:

1.a≤b новый элемент передвигать не нужно

2.b≤a≤c в этом случае новый элемент нужно передвинуть вверх и его приоритет будет выше c, что и необходимо, таким образом рассмотрим алгоритм полностью решающий проблему. Время выполнения INSERT пропорционально длине пути, который пройдет новый элемент от листа до конечной точки О(log2(n))

36. Реализация частично упорядоченного двоичного дерева двоичной кучей.

Дерево частично упорядоченно, сбалансировано и на самом нижнем уровне все литья «сдвинуты влево». Благодаря этому в качестве представления можно использовать двоичную кучу, а именно массив А, в котором 1-ые n позиций соответствуют n узлам дерева. Ячейка А[1] содержит корень дерева, левый сын A[i], если он существует, находится в ячейке A[2i], а правый A[2i + 1].

Обрат. соотношение имеет вид: если сын находится в A[i], i >1, то его родитель находится в ячейке [i div 2]. При таком заполнении массива узлы дерева заполнятся ячейками с A[1] по A[n] последовательно, уровень за уровнем, а внутри уровня слева на право.

Если объявим когнст. maxsize (максимальное число элементов), processtype (случайная расстановка очереди с приоритетом процессов выполненняемых на ЭВМ)

АТД (очередь с приоритетом) можно объявить так:

type

PRIORITYQUEUE = record

contents: array [1..maxsize] of processtype;

last: integer; // last – курсор используемый в последовательности используемых ячеек массива его текущим состоянием.

end;

Рассмотрим реализацию различных операторов АТД, при этом будем полагать, что в нашем расположении находится P(x) и return( ) возвращает результат работы и прерывает работу вызвавшей ее функции.

procedure MAKENULL (var A: PRIPRITYQUEUE);

begin A.last

procedure INSERT (var A: PRIORITYQOEOE; x: processtype); var i: integer;

temp: processtype;

begin

if A.last > = maxsize then error (‘очередь пуста’) else begin

A.contents [A.last]:=x; i:=A.last;

Далее цикл while перемещает новый элемент x вверх по дереву. while (i >1) out (p(A.contents [i]) < p(A.contents [i div 2])) do begin temp:=A.contents [i];

A.contents:=A.contents [i div 2];

A.contents [i div 2]:=temp;

i:= i div 2;

end;

end; end; //конец INSERT

function DELETEMIN (var A: PRIORITYQUEUE)^precesstype; //ссылка на удаленный более приоритетный элемент

var i, j:integer; temp: procestype;

minimum:^proccesstype;

begin if A.last = othen error (‘очередь пуста’) else begin

new (minimum); //создание новой ячейки для хранения типов processtype, адрес этой ячейки передается переменной minimum

minimum^:=A.contents [1]; //во временную ячейку отправляется наиболее приоритетный

элемент

A.contents [1]:=A.contents[A.last]; //размещаем в корне элемент из последнего листа

A.last:=A.last-1; i:=1;

Далее while перемещает элемент, попавший в корень, вниз по дереву, если это необходимо while i<=(A.last div 2) do begin

В следующем условном операторе узел j будет в одном i с наибольшим приоритетом или, если 2i=A.last будет просто сыном i

if (p(A.contents [2*i]) < p(A.contents [2*i+1])) or (2*i = A.last) then j:=2*i;

else j:=2*i+1;

В следующем условном операторе существует обмен передвигаемого элемента с его сыном имеющим наибольший приоритет

if (p(A.contents [i]) > (p(A.contents [j])) begin temp:=A.contents [i];

A.contents [i]:=A.contents [j];

A.contents [j]:=temp;

i:=j;

end

else return (minimum); //перемещение далее невозможно

end;

return (minimum); //элемент добрался до листа end;

end; // конец DELETEMIN

37. Нагруженные деревья – основные понятия. Реализации узлов нагруженного дерева (АТД TREENODE). Основные операторы для АТД TREENODE.

Дана структура применения для хранения множества элементов являющихся символьными строками, такие структуры используются, когда основные операторы должны быть оператором

INSERT, DELETE, MAKENULL и PRINT.

Качественное описание структуры в нагруженном дереве, каждое ребро помечено 1-ним символом основного алфавита.

Путь от корня к листу соответствует одномерному слову, который задается последовательностью символов. Дополнительно к основному алфавиту, деревья используют специальный символ «$» (маркёр) конца слова, следовательно любое слово заканчивается «$». Благодаря этому, например словам СОК и СОКРАТ будут соответствовать разные ветви дерева, иначе множество ребер соответствующим СОК не будет соответствовать множеству ребер СОКРАТ. При таком построении его узлы будут соответствовать префиксам слов, причем собственные префиксы словами не считаются.

Пример нагруженного дерева приведен на рис. 4.11

Вводим 2-ва абстрактных типа данных:

1.АТД TREE (собственно нагруженное дерево)

2.АТД TREENODE (узел нагруженного дерева)

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

Наиболее простая реализация узла нагруженного дерева является массив указателей на узлы. Индексирование символов расширенного алфавита:

type

chars=(‘a’, ‘б’, … , ‘я’, ‘$’); //множество символьного расширенного алфавита

TREENODE = array [chars] of ^ TREENODE;

var node: TREENODE;

Наглядно переменную NODE, если оно отображает 2-й узел на 2-м уровне, можно интерпретировать так:

Элемент node [‘0’] – это указатель на 2-й узел 3-го уравня

node [‘1’] является указателем на 3-й уровень 3-го узла

node [‘a’] … node [‘я’], node [$] nil

Если дан символ ξ действующий в дереве, то ребро node [ξ] будет указывать на номер в который входит соответствующее ребро, в противном случае node [ξ] получит nil

for c:=’a’ to ‘$’ do node [c]:=nil;

node [‘$’] всегда либо nil, либо указатель на себя, т.е петля.

Оснxовные операторы для АТД TREENODE:

Создание пустого узла (листа) procedure MAKENULL (var node TREENODE);

var c: chars;

begin

end;x

Передача указателя элементу массива

procedure ASSIGN (var node: TREENODE; c: chars; p:^TREENODE); begin node [c]:=p;

end;x

Получение указателя ассоцир. с определенным символом в узле function VALUEOF (var node: TREENODE; c: chars):^TREENODE; begin

 

return (node [c]);

end;x

Передача элементу массива индексированного конкретным символом указатель на новый

 

узел

procedure GETNEW (var node: TREENODE; c: chars); begin

new (node [c]); //создание нового узла, который будет адресовываться node [c] MAKENULL (node [c]^); //инициализация всех элементов массива ненулевым адресом

Реализация узлов нагруженного дерева может быть очень не экономичной: если общее число различных префиксов = p и при этом величина N*p существенно больше l всех слов в хранилище, то

вузлах нагруженного дерева будет …

38.Реализация нагруженного дерева (АТД TREE). Структура программы для проверки орфографии с помощью нагруженного дерева.

АТД TREE формально можно определить, как указатель на узел валяющимся корнем дерева, иначе говоря нагруженное дерево можно объявить так:

type

TREE =^ TREENODE

Следующая интерпретация как множество слов

var words: TREE;

Определим еще 1-н тип: WordType, как массив символов в составе которого есть хотя бы один символ конца слова «$», тогда любое x можно задать как переменную типа WordType, считая, что конкретное слово составляют те символы которые стоят до маркёра.

Соответствующую процедуру insert, т.е вставку x в дерево можно определить так:

procedure INSERT (x: WordType; var words: TREE);

var i: integer; t: TREE; //i – счетчик, t – указатель на поддеревья

begin

i=1;

t:=words;

while x [i] < > ‘$’ do begin

if VALUE of (t^, x [i]) = nil then //если текущий узел не имеет сына по ребру не соответствующий символу x [i]. VALUE of – возвращает указатель ассоциирующийся с символом x[i] в узле разыменования

GETNEW (t^, x [i]); //передача разыменования t индексированному указателю

t:=VALUEOF (t^, x [i]; //теперь в узле t разыменованное ребро помеченное символом x [i] обязательно будет указывать на сына, поэтому все это будет означать продвижение к сыну t разыменов.

i:=i+1; //перемещение по слову x

end;

По окончании while мы или дойдем до кольцевого ребра помеченного «$», или построим новую ветку.

ASSIGN (t^, ‘$’, t); //эта функция сделает петлю на $, т.е ребро помеченное $ превратится в петлю.

Аналогично для АТД TREE можно построить оператор DELETE

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

Псевдокоды такой программы:

MAKENULL (A);

while not eof (input) do //цикл чтения входного файла

begin read (input, nextword);

INSERT (nextword, A);

end;

while not eof (dictionary) do //читаем словарь

begin read (dictionary, nextword);

DELETE (nextword, A)

end;

39. Структура 2-3 дерева. Поиск записи с заданным ключом в 2-3 дереве.

2-3 деревья обладают следующими свойствами:

Каждый внутренний узел, в том числе корень должен иметь 2-3 сына

Пустое дерево и дерево с одним листом 2-3 деревья

Предположим, что на множестве элементов «≤» задан линейный порядок.

Каждая запись индефицирует элемент, пусть имеется ключевое поле значение которого используется для упорядоченного элемента. В каждый внутренний узел, в том числе и корень, записывается ключевое наименование элемента среди потомков 3-го сына, если он есть. Нужно учитывать, что в дереве каждый лист считается потомком самого себя, т.е элементы множества содержаться в листах, а промежуточные листы содержат служебную информацию.

На рис. 4.12 показана структура 2-3 дерева (ребра – прямоугольники, листья – овалы)