Изменения

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

Толстая куча на избыточном счётчике

574 байта добавлено, 16:35, 4 июня 2013
Нет описания правки
|neat = 1
|definition=
Определяем '''толстое дерево''' <tex>F_k</tex> ранга <tex>k</tex>, <tex>~(k = 0, 1, 2, ~\dots )</tex> следующим образом:
*Толстое дерево <tex>F_0</tex> ранга ноль состоит из единственного узла. <br>
*Толстое дерево <tex>F_k</tex> ранга <tex>k</tex>, для <tex>k = 1, 2, 3,\dots </tex>, состоит из трех деревьев <tex>F_{k-1}</tex> ранга <tex>k</tex>,таких, что корни двух из них являются самыми левыми потомками корня третьего.
*В толстом дереве ранга <tex>k</tex> ровно <tex>3^k</tex> узлов. <br>
*Для любого натурального числа <tex>n</tex> существует лес из толстых деревьев, в котором ровно <tex>n</tex> узлов. Такой лес можно построить, включив в него столько деревьев ранга <tex>i</tex>, каково значение <tex>i</tex>-го разряда представления числа <tex>n</tex> в троичной системе счисления. Заметим, что для построения такого леса можно использовать и избыточные троичные представления.
*Толстый лес из <tex>n</tex> узлов содержит <tex>O(n\log({n)})</tex> деревьев.
|proof=
}}
|neat =
|definition=
'''лесЛес''' будем называть '''нагруженным''', если он состоит из нескольких толстых деревьев, ранги которых не обязательно попарно различны и узлам которых взаимно однозначно поставлены в соответствие элементы взвешенного множества.
}}
{{Определение
|neat =
|definition=
'''Узел''' в '''нагруженном лесе''' назовем '''неправильным''', если его ключ меньше ключа его родителя.
}}
{{Определение
*<tex>Key</tex> {{---}} ключ элемента, приписанного узлу дерева
*<tex>Parent</tex> {{---}} указатель на родителя
*<tex>LestLeft</tex> {{---}} указатель на ближайшего левого брата
*<tex>Right</tex> {{---}} указатель на ближайшего правого брата
*<tex>LChild</tex> {{---}} указатель на самого левого сына
*<tex>Rank</tex> {{---}} ранг узла.
"Братья" связаны (узлы корневых деревьев, а также сыновья каждого узла) объединены в двусвязный список при помощи указателей <tex>Left</tex> и <tex>Right</tex>. У самого левого (правого) "брата" в этом списке указатель <tex>Left</tex> (<tex>Right</tex>) равен <tex>NULL</tex>.
[[Файл:FatHeapExample.png |400px|thumb|right|Пример толстого дерева <tex>F_0, F_1, F_2, F_3</tex>Представление леса списком]]
=Вспомогательные структуры=
|neat =
|definition=
'''Избыточным ''' <tex>b</tex>-арным представлением числа <tex>x</tex> будем называть последовательность <tex>d = d_n, d_{n-1}, ... d_0</tex>, такую что
<tex dpi = "150">x = {\sum\limits^{n}_{i = 0} {d_i}}{b^i}</tex>
|neat =
|definition=
Назовем <tex>b</tex>-арное избыточное представление числа '''регулярным''', если в нем между любыми двумя цифрами, равными <tex>b</tex> , найдется цифра, отличная от <tex>b-1</tex>.
}}
<br>
Величину <tex>L'(i)</tex> будем называть прямым указателем.
 
}}
===фиксация цифры===
Фиксацией цифры <tex>b</tex>, стоящей в <tex>i</tex>-м разряде представления <tex>d</tex>, (Fix(i)) назовем операцию, заключающуюся в обнулении цифры <tex>d_i</tex> и инкрементировании цифры <tex>d_{i+1}</tex>, при этом если <tex>i=n</tex> , то полагаем <tex>d_{i+1} = 1</tex>. При каждом выполнении операции фиксации будем обновлять значение <tex>L'(i)</tex>. Очевидно, при <tex>b>2</tex> операцию <tex>Fix(i)</tex> можно выполнить следующим образом:
<code>
Fix(i) '''if(''' d[i] == b): d[i] = 0; d[i + 1]++; '''if(''' d[i + 1] == b - 1):
L'[i] = L'[i + 1]
'''else''': L'[i] = i + 1;
</code>
Инкрементирование <tex>i</tex>-й цифры избыточного представления <tex>d</tex> <tex>Inc(i)</tex> можно выполнить так:
<code>
Inc(i) Fix(i); '''if ''' (d[i] == b - 1) '''or ''' (d[i] == b - 2): Fix(L'[i]); d[i]++; Fix(i);
</code>
}}
'''корневой Корневой счетчик''' представляем расширяющимся массивом <tex>RootCount</tex> , каждый элемент которого — запись с тремя полями:
*<tex>RootCount[i].Value</tex> {{---}} <tex>i</tex>-й разряд равный количеству деревьев ранга <tex>i</tex>.
*<tex>RootCount[i].ForvardPointerForwardPointer</tex> {{---}} прямой указатель <tex>i</tex>-го разряда.*<tex>RootCount[i].ListPointer</tex> {{---}} указатель на список деревьев ранга <tex>i</tex>, присутствующих в толстой куче. Деревья в этом списке связаны при помощи указателя <tex>Right</tex> корневых узлов связываемых деревьев. Если в куче нет деревьев ранга <tex>i</tex> , то указатель <tex>ListPointer</tex> равен <tex>NULL</tex>.
''Заметим, что если значение равно нулю, то нам неважно значение указателя'' <tex>RootCount[i].ListPointer</tex>.
Обновление прямого указателя <tex>i</tex>-го разряда корневого счетчика заключается в выполнении следующего псевдокода:
<code>
UpdateForwardPionter(i) '''if ''' RootCount[i + 1].Value == 3 - 1: RootCount[i].ForwardPointer = RootCount[i + 1].ForwardPointer; '''else''': RootCount[i].ForwardPointer = i + 1;
</code>
===Корректировка при вставке ===
Корректировка списочной части <tex>i</tex>-го разряда корневого счетчика при вставке в кучу нового дерева ранга <tex>i</tex> ~(<tex>InsertTree(i,p))</tex>). Эта процедура вставляет новое дерево ранга <tex>i</tex> (на него указывает указатель <tex>p</tex>) в списочную часть <tex>i</tex> -го разряда корневого счетчика <tex>RootCount</tex> выглядит так:
<code>
InsertTree(i, p) p1 = RootCount[i].ListPointer; '''if ''' RootCount[i].Value != <tex> \ne </tex> 0: p.Right = p1; '''else''': p.Right = NULL; p.Left = NULL; RootCount[i].ListPointer = p;
</code>
===Корректировка при удалении===
Корректировка списочной части <tex>i</tex>-го разряда корневого счетчика при удалении из кучи дерева ранга <tex>i</tex> ~(<tex>DeleteTree(i,p))</tex>). Эта процедура удаляет дерево ранга <tex>i</tex> (на него указывает указатель <tex>p</tex>) из списочной части <tex>i</tex>-го разряда корневого счетчика <tex>RootCount</tex> . Будем считать, что указанное дерево присутствует в куче. Процедура заключается в выполнении следующего псевдокода:
<code>
DeleteTree(i, p) p1 = RootCount[i].ListPointer; '''if(''' p1 == p): RootCount[i].ListPointer = p.Right; j = 1; '''while''' (j <= tex> \le </tex> RootCount[i].Value) '''and ''' (p1.Right != <tex> \ne </tex> p) do: p1.Right = p.Right;
</code>
<code>
Fastening (p1, p2, p3) '''if''' (p1.Key <= tex> \le </tex> p2.Key) '''and ''' (p1.Key <= tex> \le </tex> p3.Key): MinP = p1; p1 = p2; p2 = p3; '''if''' (p2.Key <= tex> \le </tex> p1.Key) '''and''' (p2.Key <= tex> \le </tex> p3.Key): MinP = p2; p1 = p1; p2 = p3; '''if''' (p3.Key <= tex> \le </tex> p1.Key) '''and''' (p3.Key <= tex> \le </tex> p2.Key) MinP = p3; p1 = p1; p2 = p2; p1.Right = p2; p1.Left = NULL; p1.Parent = MinP; p2.Right = MinP.LChild; p2.Left = p1; p2.Parent = MinP; '''if(''' MinP.LChild != <tex> \ne </tex> NULL): MinP.LChild.Left = p2; MinP.LChild = p1; MinP.Rank = MinP.Rank + 1; MinP.Right = NULL; MinP.Left = NULL; '''return ''' MinP;
</code>
<code>
GetKey(p) '''if(''' p == NULL): Min = <tex>\infty</tex>; '''else''': Min = p.key; '''return ''' Min;
</code>
Функция <tex>MinKeyNodeRoot(p)</tex>, которая по указателю <tex>p</tex> на списочную часть разряда корневого счетчика возвращает указатель на корневой узел с минимальным ключом:
<code>
MinKeyNodeRoot(p) p1 = p; MinP = p1; '''while ''' p1 != <tex> \ne </tex> NULL : '''if(''' p1.Key < MinP.Key): MinP = p1; p1 = p1.Right; '''return ''' MinP;
</code>
<code>
rmFixRootCount(i) '''if(''' MaxRank == i): MaxRank = i + 1; RootCount[i+1].Value = 0; CountViolation[i+1].Value = 0; '''else''': UpdateForwardPointer(i + 1); RootCount[i].Value = 0; p1 = RootCount[i].ListPointer; p2 = p1.Right; p3 = p2.Right; p = Fastening(p1, p2, p3); RootCount[i].ListPointer = NULL; InsertTree(i + 1, p); RootCount[i + 1].Value = RootCount[i + 1].Value + 1;
</code>
===Инкрементирование <tex>i</tex>-го разряда корневого счетчика <tex>rmIncRootCount(i,p)</tex>===
Здесь мы должны учесть работу со списочной частью и обновить прямые указатели.
<code>
rmIncRootCount(i,p) '''if''' (RootCount[i].Value == 1) '''or ''' (RootCount[i].Value == 2): '''if(=''' RootCount[Rootcount[i].ForwardPointer): '''if(''' RootCount[i].Value == 3): FixRootCount(i); InsertTree(i,p); RootCount[i].Value = RootCount[i].Value + 1; UpdateForwardPointer(i); '''if(''' rootcount[i].Value == 3): FixRootCount(i);
</code>
Процедура удаления дерева из кучи подразумевает наличие в куче этого дерева. Пусть удаляемое дерево имеет ранг <tex>i</tex> . Тогда значение <tex>i</tex>-го разряда избыточного корневого представления не равно нулю. То есть уменьшение этого значения на единицу не испортит регулярности представления и не потребует обновления каких-либо указателей. Необходимо лишь соответствующим образом обработать списочную часть.
<code>
Delete(i, p) DeleteTree(i,p); RootCount[i].Value = RootCount[i].Value -1;
</code>
<code>
MinKey() MinP = NULL; '''for ''' i = 0 to MaxRank: p1 = MinKeyNodeRoot(RootCount[i].ListPointer); '''if ''' GetKey(p1) < GetKey(MinP): MinP = p1; '''return ''' MinP;
</code>
<code>
DeleteViolation(h2) '''for ''' i:=0 '''to ''' h2.MaxRank do: '''if (''' CountViolation[i].Value == 2): FixCountViolation(i); '''for ''' i:=0 to h2.MaxRank do : '''if(''' CountViolation[i].Value == 1): IncCountViolation(i, SearchBrother(CountViolation[i].rmFirstviolation)); FixCountViolation(i);
</code>

Навигация