Изменения

Перейти к: навигация, поиск

СНМ (реализация с помощью леса корневых деревьев)

1784 байта добавлено, 22:53, 17 декабря 2015
Нет описания правки
Для реализации СНМ будем поддерживать следующие массивы: <tex>p[x]</tex> {{---}} массив "родителей", <tex>r[x]</tex> {{---}} массив рангов.
===='''get'''====
'''function''' '''get'''(x: '''int'''): '''int''' '''if''' p[x] != x p[x] = get(p[x]) '''return''' p[x]
===='''union'''====
'''function''' '''union'''(x: '''int''', y: '''int'''): x = get(x) y = get(y) '''if''' x == y '''return''' '''if''' r[x] == r[y] r[x]++ '''if''' r[x] < r[y] p[x] = y '''else''' p[y] = x
==Асимптотика==
| ''<tex>\mathrm{union}</tex>'' || <tex>\mathrm{O(\log n)}</tex> || <tex>\mathrm{O(\mathrm{\alpha(m, n)})}</tex>
|}
Где <tex>m</tex> {{---}} общее количество операций, <tex>n</tex> {{---}} полное количество элементов, <tex>\mathrm{\alpha(m, n)}</tex> {{---}} функция, обратная к функции Аккермана (если <tex>m</tex> операций <tex>\mathrm{get }</tex> и <tex>n</tex> элементов).
Докажем, что если глубина множества (т.е. его ранг) равна <tex>k</tex>, то в нем содержится как минимум <tex>2^k</tex> элементов. Из этого свойства следует, что глубина множества с <tex>n</tex> элементами есть <tex>\mathrm{O(\log n)}</tex>, а значит и время работы операции <tex>\mathrm{get}</tex> является логарифмическим.
|}
Функция, обратная функции Аккермана <tex>\mathrm{\alpha(m, n)}</tex>, равна минимальному <tex>i</tex> такому, что <tex>\mathrm{A \left (i, \left [\dfrac{m}{n} \right ] \right )} \geqslant \log n</tex>. Как видно из таблицы значений для функции Аккермана, обратная функция для любых значений, которые могут возникнуть при решении прикладных задач, не превышает 4, то есть можно считать, что операция <tex>\mathrm{get }</tex> выполняется за константное время.
===Анализ реализации с ранговой эвристикой===
Проведем анализ реализации с ранговой эвристикой, будем доказывать более слабую оценку (итерированный логарифм <tex>\mathrm(\log^*n)</tex>).
{{Определение|definition=<tex>\mathrm(\log^*n)</tex> — минимальное число логарифмирований <tex>n</tex>, необходимое для получения значения, не превосходящего <tex>1</tex> (Например: <tex>\mathrm(\log^*_2 16) = 3</tex>)}}Рассмотрим <tex> a n </tex> операций <tex> \mathrm{union} </tex> и <tex> b m </tex> операций <tex> \mathrm{get} ( b </tex>. Далее будем считать, что <tex>m\geqslant n</tex>, так как количество операций <tex>\mathrm{union}</tex> не превосходит количество элементов множества <tex> a ) n</tex>.Не теряя общности, будем считать, что <tex> \mathrm{union } </tex> принимает в качестве аргументов представителей,
то есть <tex> \mathrm{union(v_1,v_2)} </tex> заменяем на <tex> \mathrm{union(get(v_1),get(v_2))} </tex>.
 
<tex>\mathrm(\log^*n)</tex> — минимальное число логарифмирований <tex>n</tex>, необходимое для получения значения, не превосходящего <tex>1</tex> (Например: <tex>\mathrm(\log^*_2 16) = 3</tex>)
Оценим стоимость операции <tex> \mathrm{get(v)} </tex>.
{{Утверждение
|statement=
<tex> \mathrm{R(P(v))} > \geqslant \mathrm{R(v)} </tex>
|proof=
Из Если <tex>\mathrm{v}</tex> — представитель множества, то <tex>\mathrm{P(v)}=\mathrm{v}</tex> и <tex> \mathrm{R(P(v))} = \mathrm{R(v)} </tex>. Иначе, из принципа работы функции <tex> \mathrm{get} </tex> следует:
#<tex> \mathrm{R(L(v))}>\mathrm{R(v)} </tex>.
#Между <tex> v </tex> и <tex> \mathrm{P(v)} </tex> существует путь вида: <tex> v \rightarrow \mathrm{L(v)} \rightarrow \mathrm{L(L(v))} \rightarrow \dots \rightarrow \mathrm{P(v)} </tex>.
Из последнего утверждения следует:
#{{Утверждение|statement=<tex> \mathrm{R(v)} \leqslant \log_2a log_2n </tex>.#}}{{Утверждение|statement=Количество вершин ранга <tex> i \leqslant \dfrac{an} {2^i} </tex>.|proof=Если бы это было не так, то просуммировав количество вершин всех рангов, мы получили бы число большее <tex>n</tex>. Это противоречит условию, по которому <tex>n</tex> — число всех вершин. Значит утверждение верно.}}
{{Теорема
|proof=
Рассмотрим все вызовы функции <tex>\mathrm{get(u)}</tex>. В процессе выполнения каждой операции двигаемся вверх по одному из деревьев, заканчивая поиск в его корне. Если вершина <tex>u</tex> не корень и не сын корня, то во время рекурсивных вызовов функции <tex>\mathrm{R(Pget(u))}</tex> возрастает после каждого вызова функции текущее значение <tex>get\mathrm{R(P(u))}</tex>возрастает.Пусть <tex>m</tex> — количество вызовов операции <tex>\mathrm{get(u)}</tex>, <tex>n</tex> — количество вызовов операции <tex>\mathrm{union(v, u)}</tex>, и <tex>m\geqslant n</tex>.
Разделим все вершины на <tex>4</tex> типа:
1. #<tex>u</tex> — корень. Таких вызовов <tex>\mathrm{get(u)}</tex> будет ровно <tex>m</tex>; 2. #<tex>u</tex> — сын корня. Таких вызовов <tex>\mathrm{get(u)}</tex> будет не больше чем <tex>m</tex>. Оставшиеся вершины разделим на:#Быстро растущие вызовы — такие что <tex>\mathrm{R(P(u))} \geqslant i^{\mathrm{R(u)}}</tex>, где <tex>i</tex> — число из диапазона <tex dpi="150">e ^{\frac{1}{e}} < i < 2</tex>. <tex dpi="150">(e ^{\frac{1}{e}}\approx </tex> <tex>1.44</tex><tex dpi="150">)</tex>;#Медленно растущие вызовы — <tex>\mathrm{R(P(u))} < i^{\mathrm{R(u)}}</tex>.
Оставшиеся вершины разделим на:Для первых двух типов вершин одна операция <tex>\mathrm{get(u)}</tex> работает за истинное время <tex>\mathrm{O(1)}</tex>, поэтому их суммарное время работы не превышает <tex>2\cdot m</tex>.
3. Быстро растущие вызовы — такие что При каждом вложенном вызове функции <tex>\mathrm{R(Pget(u))} \geqslant </tex> ранг вершины по условию возрастает на <tex>i^{\mathrm{R(u)}}</tex>, где . Ранг вершины может меняться в пределах от <tex>i1</tex> — число из диапазона до <tex dpi="150">e ^{\frac{1}{e}} < i < 2log_2n</tex>; 4. Медленно растущие вызовы — Значит количество рекурсивных вызовов равняется количеству возведений в степень <tex>\mathrm{R(P(u)n)} < i^{\mathrm{R(u)}}</tex>. Для первых двух типов вершин одна операция числа <tex>get(u)</tex> работает за истинное время <tex>\mathrm{O(1)}i</tex>, поэтому их суммарное время работы не превышает необходимых для достижения числа <tex>2\cdot mlog_2n</tex>. Количество итераций для быстро растущих вызовов не превосходит Или что то же самое, количеству логарифмирований по основанию <tex>\log_2 ni</tex>, так как при каждом вызове ранг вершины увеличивается, но он не может быть больше числа <tex>\log_2n</tex>. Таким образом, время на один быстро растущий вызов функции для получения <tex>get(u)1</tex> меньше или равно . Последняя операция описывается функцией <tex dpi="150130">\log^*_{i} \left (\log log_2 n \right )</tex>. Суммарное Тогда время работы <tex>m</tex> быстро растущих вызовов равняется равно <tex>\mathrm{O(m\cdot \log^* n)}</tex>.
Поскольку количество вершин с рангом <tex>k</tex> не превышает число <tex>\dfrac{n}{2^k}</tex>, то суммарное время работы медленно растущих вызовов равно
<tex dpi="150">\sum_u \limits i^{\mathrm{R(u)}}=\sum_{k=0}^{\log n} \limits \sum_{\mathrm{{R(u)}=k}} \limits i^k \leqslant \sum_{k=0}^{\log n} \limits i^k \cdot \frac{n}{2^k} \leqslant n \cdot \sum_{k=0}^{\log n} \limits \dfrac{i^k}{2^k} = \mathrm{O(n)}</tex>
</center>
В итоге получаем, что суммарное время работы операции <tex>\mathrm{get(u)}</tex> равняется <tex>T = \mathrm{O(m)} + \mathrm{O(m\cdot \log^* n)} +\mathrm{O(n)} = \mathrm{O(m\cdot \log^*n + n)}</tex>.
С учетом того факта что <tex>m\geqslant n</tex>, амортизированное время работы равно <tex>\mathrm{O(\log^* n)}</tex>.
}}
* [http://ru.wikipedia.org/wiki/Функция_Аккермана Функция Аккермана {{---}} Википедия]
* Томас Кормен, Чарльз Лейзерсон, Рональд Ривест, Клиффорд Штайн. Алгоритмы. Построение и анализ — Вильямс, 2010. - стр 589. — ISBN 978-5-8459-0857-4
 
[[Категория: Дискретная математика и алгоритмы]]
[[Категория: Структуры данных]]
60
правок

Навигация