Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
SortedSequence.h
Go to the documentation of this file.
1
32#pragma once
33
34#include <ogdf/basic/basic.h>
35#include <ogdf/basic/comparer.h>
37#include <ogdf/basic/memory.h>
38
39#include <cstdlib>
40#include <initializer_list>
41#include <random>
42#include <type_traits>
43#include <utility>
44
45namespace ogdf {
46
47template<class KEY, class INFO, class CMP, bool isConst, bool isReverse>
48class SortedSequenceIteratorBase;
49
50template<class KEY, class INFO, class CMP>
52
53template<class KEY, class INFO, class CMP>
55
56template<class KEY, class INFO, class CMP>
58
59template<class KEY, class INFO, class CMP>
61
63
70template<class KEY, class INFO, class CMP = StdComparer<KEY>>
72 friend class SortedSequenceIteratorBase<KEY, INFO, CMP, false, false>;
73 friend class SortedSequenceIteratorBase<KEY, INFO, CMP, true, false>;
74 friend class SortedSequenceIteratorBase<KEY, INFO, CMP, false, true>;
75 friend class SortedSequenceIteratorBase<KEY, INFO, CMP, true, true>;
76
78 struct Element {
79 KEY m_key;
80 INFO m_info;
82
85
87 Element(const KEY& key, const INFO& info, int height)
88 : m_key(key), m_info(info), m_height(height) {
89 m_next = (Element**)malloc(height * sizeof(Element*));
90 m_prev = (Element**)malloc(height * sizeof(Element*));
91 }
92
94
98 Element(int height) : m_height(0) {
99 m_next = (Element**)malloc(height * sizeof(Element*));
100 m_prev = (Element**)malloc(height * sizeof(Element*));
101 }
102
103 Element(const Element&) = delete;
104
107 free(m_prev);
108 free(m_next);
109 }
110
112 void grow(int newHeight) {
113 Element** p = static_cast<Element**>(realloc(m_next, newHeight * sizeof(Element*)));
114 if (p == nullptr) {
116 }
117 m_next = p;
118
119 p = static_cast<Element**>(realloc(m_prev, newHeight * sizeof(Element*)));
120 if (p == nullptr) {
122 }
123 m_prev = p;
124 }
125
127 };
128
129public:
138
140 SortedSequence(const CMP& comparer = CMP())
141 : m_comparer(comparer), m_rng(randomSeed()), m_randomBits(0, 1) {
142 initEmpty();
143 }
144
146 SortedSequence(std::initializer_list<std::pair<KEY, INFO>> initList);
147
150
152
156
159 clear();
160 delete m_dummy;
161 }
162
169
171 int size() const { return m_size; }
172
174 bool empty() const { return m_size == 0; }
175
177 iterator begin();
178
180 const_iterator begin() const;
181
183 const_iterator cbegin() const { return begin(); }
184
186 iterator end();
187
189 const_iterator end() const;
190
192 const_iterator cend() const { return end(); }
193
196
199
202
205
208
210 const_reverse_iterator crend() const { return rend(); }
211
217
219 iterator lookup(const KEY& key);
220
222 const_iterator lookup(const KEY& key) const;
223
227 iterator locate(const KEY& key);
228
232 const_iterator locate(const KEY& key) const;
233
236
239 iterator minItem() { return begin(); }
240
243
246 const_iterator minItem() const { return begin(); }
247
250
254
257
261
263
268
270 iterator insert(const KEY& key, const INFO& info);
271
273 void del(const KEY& key);
274
276 void delItem(iterator it);
277
279 void clear() {
280 Element* item = m_dummy->m_next[0];
281 while (item != m_dummy) {
282 Element* old = item;
283 item = item->m_next[0];
284 delete old;
285 }
286 m_size = 0;
287 m_height = 1;
288 m_dummy->m_next[0] = m_dummy->m_prev[0] = m_dummy;
289 }
290
292
297
300
302
306
308
312
314
318
320
325
327
332 iterator insertAfter(iterator it, const KEY& key, const INFO& info);
333
335
345 void reverseItems(iterator itBegin, iterator itEnd) {
346 reverseElements(itBegin.m_pElement, itEnd.m_pElement);
347 }
348
350
351private:
353 int m_size;
357
358 std::minstd_rand m_rng;
359 std::uniform_int_distribution<> m_randomBits;
360
361 void initEmpty() {
362 m_size = 0;
363 m_realHeight = 5;
364 m_height = 1;
365
367 m_dummy->m_next[0] = m_dummy;
368 m_dummy->m_prev[0] = m_dummy;
369 }
370
372 void grow(int newHeight);
373
374 const Element* _lookup(const KEY& key) const;
375 const Element* _locate(const KEY& key) const;
376
377 void removeElement(Element* p);
378 void insertElementAfterElement(Element* p, Element* q);
379 void reverseElements(Element* p, Element* q);
380};
381
383template<class KEY, class INFO, class CMP, bool isConst, bool isReverse>
385 friend class SortedSequence<KEY, INFO, CMP>;
386 friend class SortedSequenceIteratorBase<KEY, INFO, CMP, !isConst, isReverse>;
387 friend class SortedSequenceIteratorBase<KEY, INFO, CMP, isConst, !isReverse>;
388 friend class SortedSequenceIteratorBase<KEY, INFO, CMP, !isConst, !isReverse>;
389
390 using Element =
391 typename std::conditional<isConst, const typename SortedSequence<KEY, INFO, CMP>::Element,
394
397
398public:
401
403 template<bool isArgConst, typename std::enable_if<isConst || !isArgConst, int>::type = 0, bool isArgReverse>
407
409 // gcc9 complains since it cannot match the templated constructor above (-Werror=deprecated-copy).
413
415 const KEY& key() const {
417 return m_pElement->m_key;
418 }
419
421 typename std::conditional<isConst, const INFO, INFO>::type& info() const {
423 return m_pElement->m_info;
424 }
425
427 bool valid() const { return m_pElement != nullptr; }
428
434
441
447
454
459
464
471
476
481
482private:
485 return (m_pElement->m_next[0]->m_height > 0) ? m_pElement->m_next[0] : nullptr;
486 }
487
490 return (m_pElement->m_prev[0]->m_height > 0) ? m_pElement->m_prev[0] : nullptr;
491 }
492};
493
494template<class KEY, class INFO, class CMP>
495SortedSequence<KEY, INFO, CMP>::SortedSequence(std::initializer_list<std::pair<KEY, INFO>> initList)
496 : SortedSequence() {
497 for (const auto& p : initList) {
498 insert(p.first, p.second);
499 }
500}
501
502template<class KEY, class INFO, class CMP>
504 : m_comparer(S.m_comparer), m_rng(randomSeed()), m_randomBits(0, 1) {
505 initEmpty();
506
507 iterator it = m_dummy;
508 for (Element* pS = S.m_dummy->m_next[0]; pS != S.m_dummy; pS = pS->m_next[0]) {
509 it = insertAfter(it, pS->m_key, pS->m_info);
510 }
511}
512
513template<class KEY, class INFO, class CMP>
515 : m_comparer(S.m_comparer)
516 , m_size(S.m_size)
517 , m_height(S.m_height)
518 , m_realHeight(S.m_realHeight)
519 , m_rng(randomSeed())
520 , m_randomBits(0, 1) {
521 // move all elements to this sequence
522 m_dummy = S.m_dummy;
523
524 // initalize S with an empty sequence
525 S.initEmpty();
526}
527
528template<class KEY, class INFO, class CMP>
531 clear();
532
533 iterator it = m_dummy;
534 for (Element* pS = S.m_dummy->m_next[0]; pS != S.m_dummy; pS = pS->m_next[0]) {
535 it = insertAfter(it, pS->m_key, pS->m_info);
536 }
537
538 return *this;
539}
540
541template<class KEY, class INFO, class CMP>
544 // clear this sequence
545 Element* item = m_dummy->m_next[0];
546 while (item != m_dummy) {
547 Element* old = item;
548 item = item->m_next[0];
549 delete old;
550 }
551 delete m_dummy;
552
553 // move elements from S to this sequence
554 m_comparer = S.m_comparer;
555 m_size = S.m_size;
556 m_height = S.m_height;
557 m_realHeight = S.m_realHeight;
558 m_dummy = S.m_dummy;
559
560 // make S the empty sequence
561 S.initEmpty();
562
563 return *this;
564}
565
566template<class KEY, class INFO, class CMP>
568 if (m_size != S.m_size) {
569 return false;
570 }
571
572 Element *p = m_dummy->m_next[0], *pS = S.m_dummy->m_next[0];
573 while (p != m_dummy) {
574 if (!m_comparer.equal(p->m_key, pS->m_key)) {
575 return false;
576 }
577 p = p->m_next[0];
578 pS = pS->m_next[0];
579 }
580
581 return true;
582}
583
584template<class KEY, class INFO, class CMP>
586 const KEY& key) const {
587 int h = m_height - 1;
588 Element** pElement = m_dummy->m_next;
589
590 while (true) {
591 if (pElement[h] != m_dummy && m_comparer.less(pElement[h]->m_key, key)) {
592 pElement = pElement[h]->m_next;
593 } else if (--h < 0) {
594 if (pElement[0] != m_dummy && m_comparer.equal(pElement[0]->m_key, key)) {
595 return pElement[0];
596 }
597 return nullptr;
598 }
599 }
600}
601
602template<class KEY, class INFO, class CMP>
604 const KEY& key) {
605 return iterator(const_cast<Element*>(_lookup(key)));
606}
607
608template<class KEY, class INFO, class CMP>
610 const KEY& key) const {
611 return const_iterator(_lookup(key));
612}
613
614template<class KEY, class INFO, class CMP>
616 const KEY& key) const {
617 int h = m_height - 1;
618 Element** pElement = m_dummy->m_next;
619
620 while (true) {
621 if (pElement[h] != m_dummy && m_comparer.less(pElement[h]->m_key, key)) {
622 pElement = pElement[h]->m_next;
623 } else if (--h < 0) {
624 Element* p = (pElement[0] != m_dummy) ? pElement[0] : nullptr;
625 return p;
626 }
627 }
628}
629
630template<class KEY, class INFO, class CMP>
632 const KEY& key) {
633 return iterator(const_cast<Element*>(_locate(key)));
634}
635
636template<class KEY, class INFO, class CMP>
638 const KEY& key) const {
639 return const_iterator(_locate(key));
640}
641
642template<class KEY, class INFO, class CMP>
644 if (newHeight > m_realHeight) {
645 m_realHeight = newHeight;
646 m_dummy->grow(newHeight);
647 }
648
649 for (int i = newHeight; i-- > m_height;) {
650 m_dummy->m_next[i] = m_dummy;
651 m_dummy->m_prev[i] = m_dummy;
652 }
653 m_height = newHeight;
654}
655
656template<class KEY, class INFO, class CMP>
658 int h = 1;
659 while (m_randomBits(m_rng) == 1) {
660 h++;
661 }
662
663 if (h > m_height) {
664 grow(h);
665 }
666
667 return h;
668}
669
670template<class KEY, class INFO, class CMP>
672 const KEY& key, const INFO& info) {
673 int h = m_height - 1;
674 Element* pCurrent = m_dummy;
675
676 while (true) {
677 if (pCurrent->m_next[h] != m_dummy && m_comparer.less(pCurrent->m_next[h]->m_key, key)) {
678 pCurrent = pCurrent->m_next[h];
679
680 } else {
681 if (--h < 0) {
682 // found element?
683 if (pCurrent->m_next[0] != m_dummy
684 && m_comparer.equal(pCurrent->m_next[0]->m_key, key)) {
685 pCurrent->m_next[0]->m_info = info;
686 return iterator(pCurrent->m_next[0]);
687 }
688 break;
689 }
690 }
691 }
692
693 // add new element (key,inf)
694 m_size++;
695
696 int nh = randomHeightAndGrow();
697
698 Element* pNewElement = new Element(key, info, nh);
699 insertElementAfterElement(pNewElement, pCurrent);
700
701 return iterator(pNewElement);
702}
703
704template<class KEY, class INFO, class CMP>
706 iterator it = lookup(key);
707 if (it.valid()) {
708 delItem(it);
709 }
710}
711
712template<class KEY, class INFO, class CMP>
714 iterator it, const KEY& key, const INFO& info) {
715 m_size++;
716
717 int nh = randomHeightAndGrow();
718
719 Element* pNewElement = new Element(key, info, nh);
720 insertElementAfterElement(pNewElement, it.m_pElement);
721
722 return pNewElement;
723}
724
725template<class KEY, class INFO, class CMP>
727 OGDF_ASSERT(p->m_height <= m_height);
728
729 for (int h = 0; h < p->m_height; ++h) {
730 while (q != m_dummy && q->m_height <= h) {
731 q = q->m_prev[h - 1];
732 }
733
734 Element* r = q->m_next[h];
735 p->m_next[h] = r;
736 p->m_prev[h] = q;
737 q->m_next[h] = r->m_prev[h] = p;
738 }
739}
740
741template<class KEY, class INFO, class CMP>
743 while (p != q) {
744 Element* r = p;
745 p = p->m_next[0];
746 removeElement(r);
747 insertElementAfterElement(r, q);
748 }
749}
750
751template<class KEY, class INFO, class CMP>
753 OGDF_ASSERT(p != nullptr);
754 OGDF_ASSERT(p != m_dummy);
755
756 for (int h = 0; h < p->m_height; ++h) {
757 Element *pPred = p->m_prev[h], *pSucc = p->m_next[h];
758 pPred->m_next[h] = pSucc;
759 pSucc->m_prev[h] = pPred;
760 }
761}
762
763template<class KEY, class INFO, class CMP>
765 Element* p = it.m_pElement;
766 removeElement(p);
767
768 m_size--;
769 delete p;
770}
771
772template<class KEY, class INFO, class CMP>
774 return (m_dummy->m_next[0] != m_dummy) ? m_dummy->m_next[0] : nullptr;
775}
776
777template<class KEY, class INFO, class CMP>
780 return (m_dummy->m_next[0] != m_dummy) ? m_dummy->m_next[0] : 0;
781}
782
783template<class KEY, class INFO, class CMP>
787
788template<class KEY, class INFO, class CMP>
793
794template<class KEY, class INFO, class CMP>
797 return (m_dummy->m_prev[0] != m_dummy) ? m_dummy->m_prev[0] : 0;
798}
799
800template<class KEY, class INFO, class CMP>
803 return (m_dummy->m_prev[0] != m_dummy) ? m_dummy->m_prev[0] : 0;
804}
805
806template<class KEY, class INFO, class CMP>
810
811template<class KEY, class INFO, class CMP>
816
817}
Basic declarations, included by all source files.
Exception thrown when not enough memory is available to execute an algorithm.
Definition exceptions.h:209
Maintains a sequence of (key,info) pairs sorted by key.
reverse_iterator rend()
Returns a reverse iterator pointing to one before the first element.
SortedSequence(const CMP &comparer=CMP())
Constructs an initially empty sorted sequence.
iterator insertAfter(iterator it, const KEY &key, const INFO &info)
Adds a new element <key, info> after element it.
void delItem(iterator it)
Removes the element to which it points from the sequence.
std::minstd_rand m_rng
Random number generator.
const_iterator cend() const
Returns a const-iterator pointing to one past the last element.
bool operator==(const SortedSequence< KEY, INFO, CMP > &S)
Returns true if the keys stored in this sequence equal the keys in S, false otherwise.
int m_realHeight
actual height of head/tail arrays.
const_iterator minItem() const
Returns a const-iterator to the element with minimal key if the sequence is not empty,...
void reverseElements(Element *p, Element *q)
const_reverse_iterator crend() const
Returns a const reverse iterator pointing to one before the first element.
SortedSequence< KEY, INFO, CMP > & operator=(const SortedSequence< KEY, INFO, CMP > &S)
Assignment operator.
int m_size
number of elements stored in the sequence.
const_reverse_iterator maxItem() const
Returns a const reverse iterator to the element with maximal key if the sequence is not empty,...
void reverseItems(iterator itBegin, iterator itEnd)
Reverses the items in the subsequence from itBegin to itEnd (inclusive).
const Element * _lookup(const KEY &key) const
SortedSequenceIterator< KEY, INFO, CMP > iterator
The iterator type for sorted sequences (bidirectional iterator).
const Element * _locate(const KEY &key) const
iterator lookup(const KEY &key)
Returns an iterator to the element with key key, or a null iterator if no such element exists.
iterator begin()
Returns an iterator pointing to the first element.
int size() const
Returns the current size of the sequence, i.e., the number of stored elements.
bool operator!=(const SortedSequence< KEY, INFO, CMP > &S)
Returns false if the keys stored in this sequence equal the keys in S, true otherwise.
Element * m_dummy
dummy element representing the head and tail of the skiplist.
iterator insert(const KEY &key, const INFO &info)
Updates information for key if contained in sequence, or adds a new element <key, info>.
iterator locate(const KEY &key)
Returns an iterator to the element < k1, i1 > such that k1 is minimal with k1 ≥ key,...
reverse_iterator maxItem()
Returns a reverse iterator to the element with maximal key if the sequence is not empty,...
iterator minItem()
Returns an iterator to the element with minimal key if the sequence is not empty, an invalid iterator...
SortedSequenceReverseIterator< KEY, INFO, CMP > reverse_iterator
The reverse iterator type for sorted sequences (bidirectional iterator).
SortedSequenceConstReverseIterator< KEY, INFO, CMP > const_reverse_iterator
The const reverse iterator type for sorted sequences (bidirectional iterator).
~SortedSequence()
Destructor.
std::uniform_int_distribution m_randomBits
void del(const KEY &key)
Removes the element with key key (if such an element exists).
void insertElementAfterElement(Element *p, Element *q)
SortedSequenceConstIterator< KEY, INFO, CMP > const_iterator
The const-iterator type for sorted sequences (bidirectional iterator).
bool empty() const
Returns true if the sequence is empty, false otherwise.
const_reverse_iterator crbegin() const
Returns a const reverse iterator pointing to the last element.
void grow(int newHeight)
void clear()
Removes all elements from the sorted sequence.
iterator end()
Returns an iterator pointing to one past the last element.
int m_height
current height of head/tail.
reverse_iterator rbegin()
Returns a reverse iterator pointing to the last element.
void removeElement(Element *p)
const_iterator cbegin() const
Returns a const-iterator pointing to the first element.
Iterators for sorted sequences.
SortedSequenceIteratorBase(const SortedSequenceIteratorBase< KEY, INFO, CMP, isArgConst, isArgReverse > &it)
Copy constructor.
SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > operator++(int)
Moves the iterator one item forward (postfix notation)
SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > & operator++()
Move the iterator one item forward (prefix notation)
std::conditional< isConst, constINFO, INFO >::type & info() const
Returns the info of the sequence element pointed to.
bool operator==(const SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > &it) const
Equality operator.
const KEY & key() const
Returns the key of the sequence element pointed to.
SortedSequenceIteratorBase(Element *pElement)
Creates an iterator pointing to pElement.
SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > operator--(int)
Moves the iterator one item backward (postfix notation)
SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > & operator--()
Moves the iterator one item backward (prefix notation)
SortedSequenceIteratorBase()
Creates an invalid (null-) iterator.
SortedSequenceIteratorBase(const SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > &it)
Copy constructor.
SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > & operator=(const SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > &it)
Assignment operator.
bool valid() const
Returns true if the iterator points to an element.
SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > pred() const
Returns an iterator pointing to the previous element in the sequence.
typename std::conditional< isConst, const typename SortedSequence< KEY, INFO, CMP >::Element, typename SortedSequence< KEY, INFO, CMP >::Element >::type Element
bool operator!=(const SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > &it) const
Inequality operator.
SortedSequenceIteratorBase< KEY, INFO, CMP, isConst, isReverse > succ() const
Returns an iterator pointing to the next element in the sequence.
SortedSequence< KEY, INFO, CMP >::Element * succElement() const
SortedSequence< KEY, INFO, CMP >::Element * predElement() const
Declarations for Comparer objects.
Definition of exception classes.
#define OGDF_THROW(CLASS)
Replacement for throw.
Definition exceptions.h:67
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:52
#define OGDF_NEW_DELETE
Makes the class use OGDF's memory allocator.
Definition memory.h:85
long unsigned int randomSeed()
Returns a random value suitable as initial seed for a random number engine.
Declaration of memory manager for allocating small pieces of memory.
The namespace for all OGDF objects.
Internal structure to hold the items and internal forward/backward pointers of the skiplist.
int m_height
the height of the skiplist element.
Element ** m_next
array of successor elements.
Element ** m_prev
array of predecessor elements.
void grow(int newHeight)
Increases the element's height to newHeight.
Element(int height)
Creates a dummy (stop) element with given height.
Element(const Element &)=delete
INFO m_info
stores the associated information.
Element(const KEY &key, const INFO &info, int height)
Creates a skiplist element for(key,info) and given height.