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

Графы. Модели вычислений. Структуры данных

..pdf
Скачиваний:
231
Добавлен:
01.05.2014
Размер:
2.53 Mб
Скачать

0

1

1

0

7

0

4

 

 

 

0 2

 

1

2

3

4

5

6

7

p

3

1

3

6

5

6

3

h

1

0

2

0

0

1

0

Рис. 7

 

 

 

2

3

 

 

 

 

0

5

 

 

 

 

 

 

 

 

 

1

1

 

0

7

1

6

 

 

 

0

2

 

 

 

 

 

0

4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

2

3

4

5

6

7

 

 

p

3

 

1

3

6

5

3

3

 

 

h

1

 

0

2

0

0

1

0

Рис. 8

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

Лемма 1. В результате выполнения любой последовательности операций из набора {СОЗДАТЬ, ОБЪЕДИНИТЬ, НАЙТИ} над пустой коллекцией разделенных множеств для любого узла x выполняется неравенство n[x] 2h(x), где n[x] – количество узлов в поддереве с корнем х, h[x] – высота узла х.

Доказательство. Очевидно, перед первым применением операции

211

ОБЪЕДИНИТЬ для любого узла x имели n[x] = 1, h[x] = 0 и, следовательно, n[x] 2h(x). Операции СОЗДАТЬ и НАЙТИ не могут нарушить доказываемого неравенства, поэтому доказательство можно провести индукцией по количеству применений операции ОБЪЕДИНИТЬ.

Предположим, что перед очередным применением операции ОБЪЕДИНИТЬ (х, у) доказываемое неравенство все еще остается верным, тогда если высота узла x меньше высоты узла y, то дерево, полученное с помощью ОБЪЕДИНИТЬ (х, у), имеет корень y, а высоты узлов х и у не изменились. Количество узлов в дереве с корнем х не изменилось, а количество узлов в дереве с корнем у увеличилось. Таким образом, как для узлов x, y, так и для всех остальных неравенство сохраняется. Случай, когда высота узла x больше высоты узла y, аналогичен рассмотренному.

Если же высоты деревьев с корнями х и у до выполнения операции были одинаковы (h[x] = h[y] = h), то узел у становится родителем узла х, высота узла у увеличивается на 1, а высота узла х не изменяется. Пусть после выполнения операции величины h[x], h[y], n[x], n[y] становятся равными соответственно h' [x], h' [y], n' [x], n' [y], тогда имеем h' [y] = = h [y] + 1, h'[x] = h[x], n'[x] = n[x], n'[y] = n[y] + n[x]. По предположению индукции, имеем n[y] 2h[y] и n[x] 2h[x]. Следовательно, после выполне-

ния рассматриваемой операции для узлов x и y имеем соотношения n'[x] =

= n[x] 2h[x] = 2h'[x] и n'[y] = n[y] + n[x] 2h[y] + 2h[x] = 2h + 1 = 2h'[y]. Таким образом, утверждение леммы остается верным и в этом случае.

Лемма 2. Если за время работы, начавшейся с пустой коллекции, операция СОЗДАТЬ применялась n раз, то для любого h 0 число k узлов высоты h удовлетворяет неравенству k n/2h.

Доказательство. Пусть x1, x2, ..., xk – все узлы высоты h, тогда по лемме 1 при i = 1, 2, …, k справедливы неравенства n [xi] 2h. Следовательно,

n n [x1] + n [x2] + ...+ n [xk] k2h,

откуда и следует требуемое неравенство k n/2h.

Следствие 1. В результате выполнения любой последовательности операций из набора {СОЗДАТЬ, ОБЪЕДИНИТЬ, НАЙТИ} над пустой коллекцией разделенных множеств для любого узла x имеет место неравенство h[x] log n.

Доказательство. Дерево максимальной высоты образуется, очевидно, лишь тогда, когда все n элементов объединяются в одно множество. Для

212

такого дерева количество k узлов максимальной высоты h равно 1, по лемме 2 имеем 1 = k n / 2h, откуда 2h n и, следовательно, h log n.

Следствие 2. Время выполнения операции НАЙТИ есть O(log n). Следствие 3. При реализации разделенных множеств с использовани-

ем рангов время выполнения m операций ОБЪЕДИНИТЬ и/или НАЙТИ есть величина O(m·log n).

Замечание. При реализации операции объединения подмножеств в качестве ранга узла можно использовать количество узлов в поддереве с корнем в данном узле. Утверждение леммы 1 будет справедливым и в этом случае, следовательно, сохранятся и оценки времени выполнения операций.

2.6.Представление разделенных множеств

сиспользованием рангов вершин и сжатия путей

Предыдущий способ реализации разделенных множеств можно еще улучшить за счет усовершенствования реализации операции НАЙТИ(х, y). Она теперь будет выполняться в два прохода. При первом проходе находится корень у того дерева, которому принадлежит х. При втором проходе из х в у все встреченные узлы делаются непосредственными потомками узла у. Этот прием, как увидим ниже, намного уменьшает время выполнения последующих операций НАЙТИ.

Реализация операций c использованием рангов вершин и сжатия путей. Рассматриваемая реализация не требует новых полей данных по сравнению с предыдущим случаем. Как и прежде, для каждого узла i будем хранить указатель p[i] на его родителя и ранг r [i], который теперь не обязательно будет равен высоте дерева с корнем i. Он будет равен этой высоте, если из последовательности применяемых операций удалить все операции НАЙТИ.

Операция СОЗДАТЬ(x) выполняется с помощью операторов

begin p[x]:= x; r[x] := 0 end;

В качестве родителя узла х берется тот же самый х, а его рангом считаем 0. Таким образом, время выполнения операции есть константа.

Операция ОБЪЕДИНИТЬ (x, y) выполняется как и прежде, разница лишь в том, что вместо массива h используется массив r. Время выполнения операции – константа.

213

procedure ОБЪЕДИНИТЬ (x, y); begin

if (r [x] < r [y]) then p [x] := y else if (r [x] > r [y]) then p [y] := x else {p [x] := y; r [y] := r [y] + 1}

end;

Операция НАЙТИ (x, y), как уже говорилось, выполняется в два прохода. При первом проходе мы идем от узла х к его родителю, потом к родителю его родителя и так далее, пока не достигнем корня у дерева, содержащего узел х. При втором проходе из х в у все встреченные на этом пути узлы делаются непосредственными потомками узла у. Будем называть это «сжатием путей». Очевидно, как и раньше, время выполнения одной такой операции есть O(log n). Но ниже будет доказано, что время выполнения m таких операций на самом деле меньше, чем O(m·log n). Заметим, что при выполнении этой операции ранги узлов не изменяются.

procedure НАЙТИ (x, y); begin

z := x; while (р[x] x) do x := p [x];

y := x; while (p [z] z) do {z1 := z; z := p [z]; p [z1]:= y} end;

2.7. Анализ трудоемкости

Для анализа трудоемкости выполнения операций нам потребуются две функции. Одна из них, b(n), является суперэкспонентой и определяется следующим образом:

b(0) = 0, b(n) = 2b(n–1) при n > 0.

Вторая – суперлогарифм log *n, по основанию 2, определяемая соотношением:

log *n = max{k: b(k) n}.

Суперлогарифм является в некотором смысле обратной функцией к суперэкспоненте, log *(b (n)) = n. Значения функций log *n и b (n) при нескольких значениях аргументов приведены в следующих таблицах.

n

0

1

2

3

4

5

6

b(n)

0

1

2

4

16

65536

265536

214

n

0

1

2

3

4

5

15

16

65535

65536

265536–1

log*n

0

1

2

2

3

3

3

4

4

5

5

Ребро (x, p(x)) при текущем состоянии коллекции назовем корневым, если p(x) корень и p(x) = x (петля); назовем его прикорневым, если p(x) корень и p(x) x, в противном случае – внутренним.

Отметим следующие свойства коллекции на множестве из n элементов. Прикорневое ребро может превратиться во внутреннее, а корневое – в прикорневое только при выполнении операции ОБЪЕДИНИТЬ.

Внутреннее ребро (x, y) при первом же выполнении операции НАЙТИ, «проходящей через него», исчезает, но вместо него появляется прикорневое ребро (x, y), при этом r (y) >r (y), следовательно, внутреннее ребро «участвует в поиске» не более одного раза.

Если при выполнении очередной операции ОБЪЕДИНИТЬ(x, y) узел y становится родителем узла x, то после ее выполнения справедливо неравенство r (y) > r (x).

При выполнении операции НАЙТИ ранги узлов не изменяются, но узлы могут менять своих родителей, то есть меняется структура леса.

Если перед выполнением операции НАЙТИ узел х был родителем узла у, а после выполнения этой операции родителем узла у стал узел х' х, то выполняется неравенство r (x) < r (x' ). Следовательно, даже после изменения леса в результате выполнения операции НАЙТИ ранги вдоль любого пути от листа к корню будут строго возрастать.

При выполнении операции ОБЪЕДИНИТЬ ранг любого некорневого элемента не изменяется, а ранг корня либо сохраняется, либо увеличивается на 1.

Теорема. Время выполнения последовательности операций, состоящей из n операций СОЗДАТЬ, u n – 1 операций ОБЪЕДИНИТЬ и f операций НАЙТИ, при использовании рангов и сжатия путей является величиной O((f + n) log *u).

Доказательство. Пусть s1, s2, …, sm – все операции вида СОЗДАТЬ, ОБЪЕДИНИТЬ, НАЙТИ, объявленные в формулировке теоремы и выписанные в порядке их следования, m = n + u + f. Очевидно, суммарная трудоемкость всех операций СОЗДАТЬ есть O(n), суммарная трудоемкость всех операций ОБЪЕДИНИТЬ есть O(u). Остается оценить суммарную трудоемкость операций НАЙТИ.

Через rt(x) обозначим ранг узла x, который получится после выполнения операции st, а pt(x) родитель узла x, получающийся после выполне-

215

ния этой операции.

Определим множество Gk(t) = {x: log*rt(x) = k} = {x: b(k) rt(x) < < b(k + 1)}. Для краткости будем обозначать log*rt(x) = it(x).

Поскольку ранг узла может увеличиваться лишь при выполнении операции ОБЪЕДИНИТЬ, причем не более чем на 1, то после u таких операций ранг никакого узла не может стать больше u, следовательно, максимальный индекс k, при котором Gk(t) может быть непустым, равен log *u.

Оценим теперь суммарное время, требуемое для выполнения f операций НАЙТИ; очевидно, оно пропорционально числу ребер, ведущих от сыновей к отцам и встречающихся при выполнении всех таких операций. Для оценки времени, затрачиваемого на реализацию этих операций, применим бухгалтерский прием. Отнесем расход времени на прохождение очередного ребра (x, y) от узла x к его родителю y при выполнении операции st+1 типа НАЙТИ на одну из трех разных статей расходов: «корневую», «транзитную» и «местную» в зависимости от следующих условий.

Если it(x) it(y) и y в рассматриваемый момент не является корнем, то расходы относим на статью T транзитных расходов. Если it(x) = it(y) = k и y не является корнем, то на статью Mk местных расходов в k-м диапазоне, если же y – корень, то на статью K корневых расходов.

Сумму местных расходов во всех диапазонах обозначим через

log*u

M = M k .

k=0

Тогда имеем K = O(f ), так как при каждом выполнении операции НАЙТИ проходится одно корневое и, возможно, одно прикорневое ребро.

Для транзитных переходов имеем T = O(f·log*u), так как при каждом выполнении операции НАЙТИ происходит не более log*u переходов из одного диапазона в другой.

Для оценки величины M введем потенциал ct(x) = rt(pt(x)) узла x после выполнения операции st. Если к узлу x еще не применялась операция

СОЗДАТЬ, то ct(x) = 0.

Потенциалом группы Gk(t) при текущем состоянии коллекции назовем величину

Ck (t) = ct (x).

x Gk (t )

 

Очевидно, в любой момент времени справедливы неравенства

 

Ck(t) |Gk(t)| b(k + 1).

(1)

216

Покажем, что для любого узла x при любом t = 1, 2, 3,…, m выполняется неравенство ct(x) ct–1(x).

Действительно, если st операция СОЗДАТЬ(x) то ct–1(x) = ct(x) = 0, то есть потенциал узла x, так же как, очевидно, и всех остальных, не изменяется.

Пусть st операция ОБЪЕДИНИТЬ(x, y). В случае rt–1(x) < rt–1(y) име-

ем ct(x) = rt(p(x)) = rt(y) = rt–1(y) > rt–1(x) = rt–1(p(x)) = ct–1(x) и ct(y) = ct–1(y).

Случай rt–1(x) > rt–1(y) аналогичен. В случае rt–1(x) = rt–1(y) имеем ct(y) =

=rt(p(y)) = rt(y) = rt–1(y) + 1 > rt–1(y) = rt–1(p(y)) = ct–1(y), ct(x) = rt(p(x)) =

=rt(y) = rt–1(y)+1 > rt–1(y) = rt–1(x) = rt–1(p(x)) = ct–1(x).

Пусть теперь st является операцией НАЙТИ, проходящей через узел x, и при этом pt–1(x) не корень (x получает нового родителя pt(x)). Тогда

имеем ct(x) = rt(pt(x)) = rt–1(pt(x)) > rt–1(pt–1(x)) = ct–1(x). В этом случае совершен переход по внутреннему ребру (местный или транзитный).

Итак, для любого узла x величина c(x) при выполнении операции вида СОЗДАТЬ, ОБЪЕДИНИТЬ, НАЙТИ не может уменьшиться и, следовательно,

Ck(t) Ck(t – 1).

При этом, если st – операция НАЙТИ, то у Mk(t) вершин при ее выполнении потенциал увеличится, по крайней мере, на 1, следовательно, число Mk(t) местных переходов в группе Gk(t) при ее выполнении удовлетворяет неравенству

Mk(t) Ck(t) – Ck(t – 1).

Суммируя это неравенство по всем t и учитывая неравенства (1), получаем, что число Mk местных переходов при всех операциях НАЙТИ удовлетворяет неравенству

Mk Ck(m) – Ck(0) Ck(m) |Gk| b(k + 1).

Заметим далее, что утверждение леммы 2, которая гарантирует, что количество узлов ранга r не более n/2r, остается верным и при использовании сжатия путей, так как при выполнении операции НАЙТИ ранги элементов не меняются. Следовательно, справедливы соотношения

b(k+1)1

n

 

n

 

1

 

1

 

1

 

 

2n

 

2n

 

|Gk | =

 

<

 

1

+

 

+

 

+

 

+...

=

 

=

 

.

2r

 

2

4

8

2b(k )

b(k +1)

r=b(k )

 

2b(k )

 

 

 

 

 

 

 

Отсюда

217

M k

2n

b(k +1) = 2n ,

b(k +1)

 

 

M = log*uM k = O(n log *u) .

k=0

Итак, суммарная трудоемкость выполнения f операций НАЙТИ равна

K + T + M = O(f + f log *u + n log *u) = O((f + n) log *u).

Учитывая теперь оценки трудоемкости операций СОЗДАТЬ и ОБЪЕДИНИТЬ получаем утверждение теоремы.

Замечание. Р.Е. Тарьян доказал, что время выполнения последовательности, состоящей из u операций ОБЪЕДИНИТЬ с перемешанными с ними f операциями НАЙТИ, где u n – 1, u + f = m, является величиной O(m α(m, n)). Также он показал, что эта оценка не может быть улучшена, а значит, алгоритм может потребовать для своего выполнения (mα(m,n)) времени.

Здесь α(f, n) = min{i 1: A (i, f / n ) > log n}, где A (i, j) – функция Аккермана, задаваемая равенствами:

A (1, j) = 2j при j 1,

A (i, 1) = A (i – 1, 2) при i 2,

A (i, j) = A (i – 1, A(i, j – 1)) при i, j 2.

Сводные данные о сложности операций с разделенными множествами

Реализация с помощью массива

СОЗДАТЬ (x)

O(1)

ОБЪЕДИНИТЬ (x, y)

O(n)

НАЙТИ (x, y)

O(1)

m операций

O(mn)

Реализация с помощью древовидной cтруктуры

СОЗДАТЬ (x)

O(1)

ОБЪЕДИНИТЬ (x, y)

O(1)

НАЙТИ (x, y)

O(n)

m операций

O(mn)

218

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

СОЗДАТЬ (x)

O (1)

ОБЪЕДИНИТЬ (x, y)

O(1)

НАЙТИ (x, y)

O(log n)

m операций

O(m log n)

Реализация с помощью древовидной структуры с использованием рангов и сжатия путей

СОЗДАТЬ (x)

O(1)

ОБЪЕДИНИТЬ (x, y)

O(1)

НАЙТИ (x, y)

O(log n)

m операций

O(n log*(u + 1))

 

O(m α (m, n))

219

Глава 3. ПРИОРИТЕТНЫЕ ОЧЕРЕДИ

3.1. Основные определения

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

ВСТАВИТЬ в множество новый элемент со своим ключом.

НАЙТИ в множестве элемент с минимальным ключом. Если элементов с минимальным ключом несколько, то находится один из них. Найденный элемент не удаляется из множества.

УДАЛИТЬ из множества элемент с минимальным ключом. Если элементов с минимальным ключом несколько, то удаляется один из них.

Дополнительные операции над приоритетными очередями:

ОБЪЕДИНИТЬ два множества в одно.

УМЕНЬШИТЬ ключ указанного элемента множества на заданное положительное число.

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

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

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

220