2 * Copyright 2013 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Paweł Dziepak, pdziepak@quarnos.org
8 #ifndef KERNEL_UTIL_MIN_MAX_HEAP_H
9 #define KERNEL_UTIL_MIN_MAX_HEAP_H
14 #include <SupportDefs.h>
17 template<typename Element
, typename Key
>
18 struct MinMaxHeapLink
{
26 template<typename Element
, typename Key
>
27 class MinMaxHeapLinkImpl
{
29 typedef MinMaxHeapLink
<Element
, Key
> Link
;
32 inline Link
* GetMinMaxHeapLink();
38 template<typename Element
, typename Key
>
39 class MinMaxHeapStandardGetLink
{
41 typedef MinMaxHeapLink
<Element
, Key
> Link
;
44 inline Link
* operator()(Element
* element
) const;
47 template<typename Element
, typename Key
,
48 MinMaxHeapLink
<Element
, Key
> Element::*LinkMember
>
49 class MinMaxHeapMemberGetLink
{
51 typedef MinMaxHeapLink
<Element
, Key
> Link
;
54 inline Link
* operator()(Element
* element
) const;
57 template<typename Key
>
58 class MinMaxHeapCompare
{
60 inline bool operator()(Key a
, Key b
);
63 #define MIN_MAX_HEAP_TEMPLATE_LIST \
64 template<typename Element, typename Key, typename Compare, typename GetLink>
65 #define MIN_MAX_HEAP_CLASS_NAME MinMaxHeap<Element, Key, Compare, GetLink>
67 template<typename Element
, typename Key
,
68 typename Compare
= MinMaxHeapCompare
<Key
>,
69 typename GetLink
= MinMaxHeapStandardGetLink
<Element
, Key
> >
73 MinMaxHeap(int initialSize
);
76 inline Element
* PeekMinimum() const;
77 inline Element
* PeekMaximum() const;
79 static const Key
& GetKey(Element
* element
);
81 inline void ModifyKey(Element
* element
, Key newKey
);
83 inline void RemoveMinimum();
84 inline void RemoveMaximum();
86 inline status_t
Insert(Element
* element
, Key key
);
89 status_t
_GrowHeap(int minimalSize
= 0);
91 void _MoveUp(MinMaxHeapLink
<Element
, Key
>* link
);
92 void _MoveDown(MinMaxHeapLink
<Element
, Key
>* link
);
93 bool _ChangeTree(MinMaxHeapLink
<Element
, Key
>* link
);
95 void _RemoveLast(bool minTree
);
97 Element
** fMinElements
;
100 Element
** fMaxElements
;
105 static Compare sCompare
;
106 static GetLink sGetLink
;
111 template<typename Element
, typename Key
>
112 MinMaxHeapLink
<Element
, Key
>::MinMaxHeapLink()
118 template<typename Element
, typename Key
>
119 MinMaxHeapLink
<Element
, Key
>::MinMaxHeapLink()
125 template<typename Element
, typename Key
>
126 MinMaxHeapLink
<Element
, Key
>*
127 MinMaxHeapLinkImpl
<Element
, Key
>::GetMinMaxHeapLink()
129 return &fMinMaxHeapLink
;
133 template<typename Element
, typename Key
>
134 MinMaxHeapLink
<Element
, Key
>*
135 MinMaxHeapStandardGetLink
<Element
, Key
>::operator()(Element
* element
) const
137 return element
->GetMinMaxHeapLink();
141 template<typename Element
, typename Key
,
142 MinMaxHeapLink
<Element
, Key
> Element::*LinkMember
>
143 MinMaxHeapLink
<Element
, Key
>*
144 MinMaxHeapMemberGetLink
<Element
, Key
, LinkMember
>::operator()(
145 Element
* element
) const
147 return &(element
->*LinkMember
);
151 template<typename Key
>
153 MinMaxHeapCompare
<Key
>::operator()(Key a
, Key b
)
159 MIN_MAX_HEAP_TEMPLATE_LIST
160 MIN_MAX_HEAP_CLASS_NAME::MinMaxHeap()
171 MIN_MAX_HEAP_TEMPLATE_LIST
172 MIN_MAX_HEAP_CLASS_NAME::MinMaxHeap(int initialSize
)
180 _GrowHeap(initialSize
);
184 MIN_MAX_HEAP_TEMPLATE_LIST
185 MIN_MAX_HEAP_CLASS_NAME::~MinMaxHeap()
191 MIN_MAX_HEAP_TEMPLATE_LIST
193 MIN_MAX_HEAP_CLASS_NAME::PeekMinimum() const
195 if (fMinLastElement
> 0)
196 return fMinElements
[0];
197 else if (fMaxLastElement
> 0) {
198 ASSERT(fMaxLastElement
== 1);
199 return fMaxElements
[0];
206 MIN_MAX_HEAP_TEMPLATE_LIST
208 MIN_MAX_HEAP_CLASS_NAME::PeekMaximum() const
210 if (fMaxLastElement
> 0)
211 return fMaxElements
[0];
212 else if (fMinLastElement
> 0) {
213 ASSERT(fMinLastElement
== 1);
214 return fMinElements
[0];
221 MIN_MAX_HEAP_TEMPLATE_LIST
223 MIN_MAX_HEAP_CLASS_NAME::GetKey(Element
* element
)
225 return sGetLink(element
)->fKey
;
229 MIN_MAX_HEAP_TEMPLATE_LIST
231 MIN_MAX_HEAP_CLASS_NAME::ModifyKey(Element
* element
, Key newKey
)
233 MinMaxHeapLink
<Element
, Key
>* link
= sGetLink(element
);
235 Key oldKey
= link
->fKey
;
238 if (!sCompare(newKey
, oldKey
) && !sCompare(oldKey
, newKey
))
241 if (sCompare(newKey
, oldKey
) ^ !link
->fMinTree
)
248 MIN_MAX_HEAP_TEMPLATE_LIST
250 MIN_MAX_HEAP_CLASS_NAME::RemoveMinimum()
252 if (fMinLastElement
== 0) {
253 ASSERT(fMaxLastElement
== 1);
259 Element
* element
= PeekMinimum();
260 MinMaxHeapLink
<Element
, Key
>* link
= sGetLink(element
);
261 ASSERT(link
->fIndex
!= -1);
269 MIN_MAX_HEAP_TEMPLATE_LIST
271 MIN_MAX_HEAP_CLASS_NAME::RemoveMaximum()
273 if (fMaxLastElement
== 0) {
274 ASSERT(fMinLastElement
== 1);
280 Element
* element
= PeekMaximum();
281 MinMaxHeapLink
<Element
, Key
>* link
= sGetLink(element
);
282 ASSERT(link
->fIndex
!= -1);
290 MIN_MAX_HEAP_TEMPLATE_LIST
292 MIN_MAX_HEAP_CLASS_NAME::Insert(Element
* element
, Key key
)
294 if (min_c(fMinLastElement
, fMaxLastElement
) == fSize
) {
295 ASSERT(max_c(fMinLastElement
, fMaxLastElement
) == fSize
);
296 status_t result
= _GrowHeap();
301 ASSERT(fMinLastElement
< fSize
|| fMaxLastElement
< fSize
);
303 MinMaxHeapLink
<Element
, Key
>* link
= sGetLink(element
);
305 ASSERT(link
->fIndex
== -1);
307 link
->fMinTree
= fMinLastElement
< fMaxLastElement
;
309 int& lastElement
= link
->fMinTree
? fMinLastElement
: fMaxLastElement
;
310 Element
** tree
= link
->fMinTree
? fMinElements
: fMaxElements
;
312 tree
[lastElement
] = element
;
313 link
->fIndex
= lastElement
++;
316 if (!_ChangeTree(link
))
323 MIN_MAX_HEAP_TEMPLATE_LIST
325 MIN_MAX_HEAP_CLASS_NAME::_GrowHeap(int minimalSize
)
327 minimalSize
= minimalSize
% 2 == 0 ? minimalSize
: minimalSize
+ 1;
328 int newSize
= max_c(max_c(fSize
* 4, 4), minimalSize
);
330 size_t arraySize
= newSize
* sizeof(Element
*);
332 = reinterpret_cast<Element
**>(realloc(fMinElements
, arraySize
));
333 if (newBuffer
== NULL
)
335 fMinElements
= newBuffer
;
337 newBuffer
+= newSize
/ 2;
338 if (fMaxLastElement
> 0)
339 memcpy(newBuffer
, fMinElements
+ fSize
, fSize
* sizeof(Element
*));
340 fMaxElements
= newBuffer
;
347 MIN_MAX_HEAP_TEMPLATE_LIST
349 MIN_MAX_HEAP_CLASS_NAME::_MoveUp(MinMaxHeapLink
<Element
, Key
>* link
)
351 Element
** tree
= link
->fMinTree
? fMinElements
: fMaxElements
;
353 if (link
->fIndex
<= 0)
356 int parent
= (link
->fIndex
- 1) / 2;
357 bool isSmaller
= sCompare(link
->fKey
, sGetLink(tree
[parent
])->fKey
);
358 if (isSmaller
^ !link
->fMinTree
) {
359 ASSERT(sGetLink(tree
[parent
])->fIndex
== parent
);
360 sGetLink(tree
[parent
])->fIndex
= link
->fIndex
;
362 Element
* element
= tree
[link
->fIndex
];
363 tree
[link
->fIndex
] = tree
[parent
];
364 tree
[parent
] = element
;
366 link
->fIndex
= parent
;
373 MIN_MAX_HEAP_TEMPLATE_LIST
375 MIN_MAX_HEAP_CLASS_NAME::_MoveDown(MinMaxHeapLink
<Element
, Key
>* link
)
379 int lastElement
= link
->fMinTree
? fMinLastElement
: fMaxLastElement
;
380 Element
** tree
= link
->fMinTree
? fMinElements
: fMaxElements
;
382 current
= link
->fIndex
;
384 int child
= 2 * link
->fIndex
+ 1;
385 if (child
< lastElement
) {
386 bool isSmaller
= sCompare(sGetLink(tree
[child
])->fKey
, link
->fKey
);
387 if (isSmaller
^ !link
->fMinTree
)
391 child
= 2 * link
->fIndex
+ 2;
392 if (child
< lastElement
) {
393 bool isSmaller
= sCompare(sGetLink(tree
[child
])->fKey
,
394 sGetLink(tree
[current
])->fKey
);
395 if (isSmaller
^ !link
->fMinTree
)
399 if (link
->fIndex
== current
)
402 ASSERT(sGetLink(tree
[current
])->fIndex
== current
);
403 sGetLink(tree
[current
])->fIndex
= link
->fIndex
;
405 Element
* element
= tree
[link
->fIndex
];
406 tree
[link
->fIndex
] = tree
[current
];
407 tree
[current
] = element
;
409 link
->fIndex
= current
;
412 if (2 * link
->fIndex
+ 1 >= lastElement
)
417 MIN_MAX_HEAP_TEMPLATE_LIST
419 MIN_MAX_HEAP_CLASS_NAME::_ChangeTree(MinMaxHeapLink
<Element
, Key
>* link
)
421 int otherLastElement
= link
->fMinTree
? fMaxLastElement
: fMinLastElement
;
423 Element
** currentTree
= link
->fMinTree
? fMinElements
: fMaxElements
;
424 Element
** otherTree
= link
->fMinTree
? fMaxElements
: fMinElements
;
426 if (otherLastElement
<= 0) {
427 ASSERT(link
->fMinTree
? fMinLastElement
: fMaxLastElement
== 1);
431 ASSERT((link
->fIndex
- 1) / 2 < otherLastElement
);
433 Element
* predecessor
;
434 if (2 * link
->fIndex
+ 1 < otherLastElement
) {
435 predecessor
= otherTree
[2 * link
->fIndex
+ 1];
436 ASSERT(sGetLink(predecessor
)->fIndex
== 2 * link
->fIndex
+ 1);
437 } else if (link
->fIndex
< otherLastElement
) {
438 predecessor
= otherTree
[link
->fIndex
];
439 ASSERT(sGetLink(predecessor
)->fIndex
== link
->fIndex
);
441 predecessor
= otherTree
[(link
->fIndex
- 1) / 2];
442 ASSERT(sGetLink(predecessor
)->fIndex
== (link
->fIndex
- 1) / 2);
444 MinMaxHeapLink
<Element
, Key
>* predecessorLink
= sGetLink(predecessor
);
446 bool isSmaller
= sCompare(predecessorLink
->fKey
, link
->fKey
);
447 if (isSmaller
^ !link
->fMinTree
) {
448 Element
* element
= currentTree
[link
->fIndex
];
449 currentTree
[link
->fIndex
] = otherTree
[predecessorLink
->fIndex
];
450 otherTree
[predecessorLink
->fIndex
] = element
;
452 int index
= link
->fIndex
;
453 link
->fIndex
= predecessorLink
->fIndex
;
454 predecessorLink
->fIndex
= index
;
456 predecessorLink
->fMinTree
= !predecessorLink
->fMinTree
;
457 link
->fMinTree
= !link
->fMinTree
;
467 MIN_MAX_HEAP_TEMPLATE_LIST
469 MIN_MAX_HEAP_CLASS_NAME::_RemoveLast(bool minTree
)
471 bool deleteMin
= fMaxLastElement
< fMinLastElement
;
473 Element
** tree
= deleteMin
? fMinElements
: fMaxElements
;
474 int& lastElement
= deleteMin
? fMinLastElement
: fMaxLastElement
;
476 ASSERT(lastElement
> 0);
478 if (lastElement
== 0 && deleteMin
== minTree
)
481 Element
* element
= tree
[lastElement
];
484 fMinElements
[0] = element
;
486 fMaxElements
[0] = element
;
488 MinMaxHeapLink
<Element
, Key
>* link
= sGetLink(element
);
490 link
->fMinTree
= minTree
;
495 MIN_MAX_HEAP_TEMPLATE_LIST
496 Compare
MIN_MAX_HEAP_CLASS_NAME::sCompare
;
498 MIN_MAX_HEAP_TEMPLATE_LIST
499 GetLink
MIN_MAX_HEAP_CLASS_NAME::sGetLink
;
502 #endif // KERNEL_UTIL_MIN_MAX_HEAP_H