Binomiální halda (Binomial heap) je halda složená z lesa binomiálních stromů. Každý prvek každého stromu má vyšší prioritu, než kterýkoliv z jeho potomků – halda se proto chová jako prioritní fronta. Binomiální halda má oproti binární a d-regulární haldě výhodu v rychlejších operacích sloučení hald () a vložení prvku (amortizovaně
).
Binomiální strom
Binonomiální strom řádu 0 obsahuje právě jeden uzel. Binomiální strom řádu n vznikne sloučením dvou stromů řádu takovým způsobem, že porovnáme prioritu kořenů obou stromů a následně ten s nižší prioritou zavěsíme pod kořen s vyšší prioritou. Binomiální halda obsahuje maximálně jeden strom každého řádu.
- Binomiální strom řádu n obsahuje
uzlů.
- Binomiální strom řádu n má hloubku n.
- Kořen binomiální stromu má n potomků.
- Kořen binomiálního stromu obsahuje jako své potomky všechny stromy nižších řádů.
Základní operace binomiální haldy
Operace jsou popsány pro min-heap – nižší prvek má vyšší prioritu. Max-heap (tj. vyšší prvek má vyšši prioritu) funguje analogicky.
Insert
Vloží prvek do haldy. Vytvoří pro prvek binomiální strom řádu 0 a provede sloučení tohoto stromu s haldou. Pokud vkládáme prvek s nižší prioritou, než je priorita současného nejnižšího prvku haldy, tak tento prvek označíme za minimální. Asymptotická složitost operace je , amortizovaná složitost
.
Return top
Vrátí a smaže z haldy prvek s nejvyšší prioritou. Odebere minimální prvek haldy, všechny podstromy přidá zpět do haldy prostřednictvím operace merge. Nalezne nový nejnižší prvek průchodem přes všechny kořeny binomiálních stromů. Asymptotická složitost operace je .
Merge
Provede sloučení haldy B do haldy A. Tato operace odpovídá sčítání dvou binárních čísel. Algoritmus prochází obě haldy od nejnižšího řádu, pokud halda B obsahuje strom řádu n a halda A nikoliv, pak jej pouze překopíruje. Pokud obě haldy obsahují stromy stejného řádu, tak je sloučí do přenosového stromu (obdoba přenosového bitu u sčítání), který zohlední pří následném spojování stromů řádu . Nakonec porovná minimální prvky obou slučovaných hald a za minimální prvek výsledné haldy označí nižší z nich. Asymptotická složitost operace je
.
Kód
001.
/**
002.
* Binomialni halda
003.
* Radi prvky dle priority (mensi == vyssi priorita)
004.
* @author Pavel Micka
005.
*/
006.
public
class
BinomialHeap<ENTITY
extends
Comparable> {
007.
private
Node<ENTITY>[] nodes;
008.
private
Node<ENTITY> min;
009.
/**
010.
* Konstruktor
011.
* @param capacity kapacita haldy
012.
*/
013.
public
BinomialHeap(
int
capacity) {
014.
min =
null
;
015.
nodes =
new
Node[((
int
) (Math.log(capacity) / Math.log(
2
))) +
2
];
016.
}
017.
018.
/**
019.
* Vlozi prvek do haldy, pokud je mensi nez aktualni minimalni, tak
020.
* jej ulozi jako nejmensi prvek
021.
* @param e
022.
*/
023.
public
void
insert(ENTITY e) {
024.
Node<ENTITY> n =
new
Node<ENTITY>(e);
025.
if
(nodes[
0
] !=
null
) merge(n, nodes[
0
]);
026.
else
nodes[
0
] = n;
027.
028.
if
(min ==
null
) min = n;
029.
else
if
(min.value.compareTo(n.value) ==
1
) min = n;
030.
}
031.
032.
/**
033.
* Smaze a vrati entitu s nejvyssi prioritou
034.
* @return entita s nejvyssi prioritou, @null, pokud je halda prazdna
035.
*/
036.
public
ENTITY returnTop() {
037.
if
(min ==
null
)
return
null
;
038.
ENTITY tmp = min.value;
039.
nodes[min.order] =
null
;
//strom vyjmeme
040.
for
(Node n : min.children) {
//a z potomku udelame nove stromu
041.
n.parent =
null
;
042.
if
(nodes[n.order] !=
null
) merge(n, nodes[n.order]);
043.
else
nodes[n.order] = n;
044.
}
045.
min.children.clear();
046.
ENTITY minVal =
null
;
047.
Node minNode =
null
;
048.
for
(
int
i =
0
; i < nodes.length; i++){
049.
if
(nodes[i] !=
null
){
050.
if
(minVal ==
null
){
051.
minVal = nodes[i].value;
052.
minNode = nodes[i];
053.
}
054.
else
if
(minVal.compareTo(nodes[i].value) ==
1
){
055.
minVal = nodes[i].value;
056.
minNode = nodes[i];
057.
}
058.
}
059.
}
060.
min = minNode;
061.
return
tmp;
062.
}
063.
064.
/**
065.
* Slouci haldy, pokud mergovana halda obsahuje mensi prvek, nez halda, na
066.
* ktere je volana operace, pak je tento prvek minimalni i ve sloucene halde
067.
* @param heap
068.
*/
069.
public
void
mergeHeaps(BinomialHeap<ENTITY> heap) {
070.
Node<ENTITY> carry =
null
;
071.
for
(
int
i =
0
; i < heap.nodes.length; i++) {
072.
if
(nodes[i] ==
null
){
073.
if
(heap.nodes[i] ==
null
){
074.
nodes[i] = carry;
075.
carry =
null
;
076.
}
else
{
077.
if
(carry ==
null
){
078.
nodes[i] = heap.nodes[i];
079.
}
else
{
080.
carry = mergeTrees(heap.nodes[i], carry);
081.
}
082.
}
083.
}
else
{
084.
if
(heap.nodes[i] ==
null
){
085.
if
(carry !=
null
){
086.
carry = mergeTrees(nodes[i], carry);
087.
nodes[i] =
null
;
088.
}
089.
}
else
{
090.
if
(carry ==
null
){
091.
carry = mergeTrees(nodes[i], heap.nodes[i]);
092.
nodes[i] =
null
;
093.
}
else
{
094.
carry = mergeTrees(carry, heap.nodes[i]);
095.
}
096.
}
097.
}
098.
}
099.
100.
if
(carry !=
null
)
throw
new
RuntimeException(
"Preteceni haldy (halda je preplnena)"
);
101.
102.
if
(
this
.min ==
null
)
this
.min = heap.min;
103.
else
if
(
this
.min !=
null
&& heap.min !=
null
&& heap.min.value.compareTo(min.value) == -
1
) min = heap.min;
104.
}
105.
106.
@Override
107.
public
String toString() {
108.
StringBuilder builder =
new
StringBuilder();
109.
for
(
int
i =
0
; i < nodes.length; i++){
110.
if
(nodes[i] ==
null
) builder.append(i +
": null\\n"
);
111.
else
builder.append(i +
":\\n"
+ nodes[i].toString() +
"\\n"
);
112.
}
113.
return
builder.toString();
114.
}
115.
116.
/**
117.
* Provede slouceni binomialnich stromu (vcetne preteceni do vyssich radu)
118.
* @param a
119.
* @param b
120.
*/
121.
private
void
merge(Node a, Node b) {
122.
if
(a.order != b.order)
123.
throw
new
IllegalArgumentException(
"Stromy nejsou stejneho radu"
);
124.
int
tmpOrder = a.order;
125.
nodes[tmpOrder] =
null
;
126.
Node newRoot =
null
;
127.
newRoot = mergeTrees(a, b);
128.
if
(nodes[tmpOrder +
1
] ==
null
) nodes[tmpOrder +
1
] = newRoot;
129.
else
merge(newRoot, nodes[tmpOrder +
1
]);
130.
}
131.
132.
/**
133.
* Slouci binomialni stromy v jeden (zavesi strom s nizsi prioritou pod strom
134.
* s vyssi prioritou)
135.
* @param a strom a
136.
* @param b strom b
137.
* @return
138.
*/
139.
private
Node mergeTrees(Node a, Node b) {
140.
Node newRoot =
null
;
141.
if
(a.value.compareTo(b.value) <
0
) {
142.
b.parent = a;
143.
a.children.add(b);
144.
a.order++;
145.
newRoot = a;
146.
}
else
{
147.
a.parent = b;
148.
b.children.add(a);
149.
b.order++;
150.
newRoot = b;
151.
}
152.
return
newRoot;
153.
}
154.
155.
/**
156.
* Reprezentuje uzel binomialni haldy
157.
* @param <ENTITY>
158.
*/
159.
private
class
Node<ENTITY
extends
Comparable> {
160.
Node<ENTITY> parent;
161.
ENTITY value;
162.
List<Node> children;
163.
int
order;
//rad binomialni haldy
164.
165.
public
Node(ENTITY value) {
166.
this
.value = value;
167.
children =
new
ArrayList<Node>();
168.
order =
0
;
169.
}
170.
171.
@Override
172.
public
String toString() {
173.
String s =
"Node value: "
+ value +
", order: "
+ order +
"\\n"
;
174.
for
(Node n : children){
175.
s += n.toString();
176.
}
177.
return
s;
178.
}
179.
}
180.
}