-
Notifications
You must be signed in to change notification settings - Fork 0
/
AVLTree.hh
1584 lines (1405 loc) · 61 KB
/
AVLTree.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/****************************************************************************
* File: AVLTree.hh
* Author: Keith Schwarz (htiek@cs.stanford.edu)
*
* An implementation of a sorted dictionary backed by an AVL tree. AVL trees
* are a type of self-balancing binary tree and were the first such structure
* to be described that guaranteed that the tree height was no greater than
* O(lg n).
*
* The idea behind the AVL tree is to ensure that for every node in the tree,
* the height of the node's left and right subtrees differ by at most one. To
* see that this ensures that the tree remains balanced, we can show that the
* minimum number of nodes n required to create a tree of height h is governed
* by the relationship n = O(lg h). Once we have this, we know that any AVL
* tree containing n nodes must have height no greater than O(lg n), and all
* the standard BST operations on such a tree will complete in time O(lg n).
* We can show this inductively. Let N(h) be the minimum number of nodes that
* could be present in a tree of height h. Clearly, N(0) = 0, since the empty
* tree can't have any nodes in it. We also have that N(1) = 1, since a tree
* of height one must have at least one node. Now, let's suppose that we are
* considering a tree of height h + 2. This means that the root of the tree
* must have some subtree that has height h + 1. Because we enforce the
* invariant that the heights of the subtrees of each node differ by at most
* one, this means that the minimum height of the other subtree of the root is
* h. This gives us that the minimum number of nodes in the tree is
* N(h + 2) = N(h) + N(h + 1) + 1, with the +1 coming from the root element.
* We claim that N(h) = F(h + 2) - 1, where F(h) is the hth Fibonacci
* number. This proof is by induction:
*
* Base cases: N(0) = 0 = 1 - 1 = F(2) - 1
* N(1) = 1 = 2 - 1 = F(3) - 1
* Inductive step: N(h + 2) = N(h) + N(h + 1) + 1
* = F(h + 2) - 1 + F(h + 3) - 1 + 1
* = F(h + 2) + F(h + 3) - 1
* = F(h + 4) - 1
* = F((h + 2) + 2) - 1
*
* It's well-known that F(h) = (1 / sqrt(5)) (P^h - p^h), where
*
* P = (1 + sqrt(5)) / 2 ~= 1.6
* p = (1 - sqrt(5)) / 2 ~= 0.6
*
* For h > 1, F(h) >= (P^h / sqrt(5)) - 1, and so we have that
*
* N(h) >= P^h / sqrt(5) - 1
* N(h) + 1 >= P^h / sqrt(5)
* sqrt(5) (N(h) + 1) >= P^h
* lg_P(sqrt(5) (N(h) + 1)) >= h
*
* And so we have that h = O(lg N(h)); that is, the height of the tree is
* O(lg n) as required.
*
* Given that a tree with this structure will have O(lg n) height, the
* question now is how we can maintain this property in the tree as we begin
* adding and removing nodes. To do this, we'll have each node keep track of
* its height in the tree. Whenever we insert a node, we can propagate the
* new height information from the newly-inserted node up to the root. If in
* the course of doing so we detect that a node has two subtrees whose heights
* differ by more than 1, we can use a series of tree rotations to fix up the
* balancing. In particular, there are two cases to consider, plus two
* symmetric cases:
*
* Case 1: We have two nodes in this configuration:
*
* a (+2)
* / \
* (+0 or +1) b Z
* / \
* X Y
*
*
*
* Here, the values in parentheses are the "balance term" for each node, which
* is defined as the difference between the height of its left and right
* subtrees. If we are in this case, then suppose that subtree Z has height
* h. Since a has a balance factor of +2, this means that the height of b
* must be h + 2, so at least one of X or Y has height h + 1, and since the
* balance term of b is not -1, either X and Y both have height h + 1, or X
* has height h + 1 and Y has height h. To fix up the balance terms here, we
* rotate along the edge from a to b to give this setup:
*
* b (+0 or -1)
* / \
* X a (+0 or +1)
* / \
* Y Z
*
* The values of these balance terms can be seen quite easily. We know that
* Z has height h, and Y either has height h + 1 or h. This means that node
* a is either at height h + 1 or h + 2, and its balance term is either +0 or
* +1. Tree X has height h + 1 as well, and so the balance term of b is
* either +0 or -1. Notice that when we started the root of this tree was at
* height h + 3, and after this operation the height is still h + 3, and so
* none of the node heights above this tree are affected.
*
* Case 2: We have three nodes in this configuration:
*
* a (+2)
* / \
* (-1) b Z
* / \
* W c (?)
* / \
* X Y
*
* Because the balance terms are the way they are, we know that if tree Z has
* height h, tree b has height h + 2. Moreover, since the balance term on the
* node is -1, we know that tree W has height h and the tree rooted at c has
* height h + 1. Consequently, at least one of X and Y have height h, and at
* most one of them has height h - 1. In this case, we do two rotations.
* First, we rotate c and b to get
*
* (+2) a
* / \
* (+1 or +2) c Z
* / \
* (+0 or +1) b Y
* / \
* W X
*
* The balance terms here are as follows. Since W has height h and X has
* height either h or h - 1, the balance term on b is either 0 or 1, and the
* height of the tree rooted at b is h + 1. Y has height either h or h - 1,
* and so the balance term on c is either +1 or +2, and it has height h + 2.
* Finally, the height of Z is defined as h, and so a has balance term +2. To
* fix up all of these imbalances, we do one more rotation to pull c above a:
*
* (+0) c
* / \
* (+0 or +1) b a (+0 or -1)
* / \ / \
* W X Y Z
*
* The term on b is unchanged from the previous step and it is still at height
* h + 1. Since Z has height h and Y has height either h - 1 or h, a has
* balance either +0 or -1, and is at height h + 1. This means that node c
* is at height h + 2 and has balance term 0. However, notice that the height
* of the root of this tree is now h + 2 instead of h + 3, meaning that the
* balance terms of nodes above this one may need to be updated in response.
*
* The logic for removing a node from an AVL tree is similar. We use standard
* techniques to remove the node in question from the BST, then run a fixup
* step like this one to fix all the imbalances in the tree. This is tricky,
* and the approach I've opted
* to use is based on the discussion from the libavl discussion at
* http://www.stanford.edu/~blp/avl/libavl.html/Deleting-from-a-BST.html.
* However, I've opted to ignore their Case 2/Case 3 distinction, since I
* don't see it as necessary.
*
* Case 1: If the node has no left child or no right child, we can just
* replace it with the child it does have (if any).
*
* a a
* / \ / \
* Z x -> Z Y
* \
* Y
*
* In this case, we need to begin a fixup pass from a, since the
* balance factors may have changed.
*
* Case 2: If the node has both children and its left child has a right child,
* then replace the node with its successor. This works by
* identifying the node's successor in its left subtree, which is the
* leftmost node of the tree. If it's not a leaf, then it's a node
* missing a left child and we can easily delete it using the logic
* in Case 1. This raises the successor's subtree (if any) by one
* level in the tree.
*
* In both cases, there is some point in the tree in which some subtree's
* height decreases by one, and we need to do apply the rebalance step to fix
* it up.
*/
#ifndef AVLTree_Included
#define AVLTree_Included
#include <algorithm> // For lexicographical_compare, equal, max
#include <functional> // For less
#include <utility> // For pair
#include <iterator> // For iterator, reverse_iterator
#include <stdexcept> // For out_of_range
#include <cassert>
/**
* A map-like class backed by a AVL tree.
*/
template <typename Key, typename Value, typename Comparator = std::less<Key> >
class AVLTree {
public:
/**
* Constructor: AVLTree(Comparator comp = Comparator());
* Usage: AVLTree<string, int> myAVLTree;
* Usage: AVLTree<string, int> myAVLTree(MyComparisonFunction);
* -------------------------------------------------------------------------
* Constructs a new, empty AVL tree that uses the indicated comparator to
* compare keys.
*/
AVLTree(Comparator comp = Comparator());
/**
* Destructor: ~AVLTree();
* Usage: (implicit)
* -------------------------------------------------------------------------
* Destroys the AVL tree, deallocating all memory allocated internally.
*/
~AVLTree();
/**
* Copy functions: AVLTree(const AVLTree& other);
* AVLTree& operator= (const AVLTree& other);
* Usage: AVLTree<string, int> one = two;
* one = two;
* -------------------------------------------------------------------------
* Makes this AVL tree equal to a deep-copy of some other AVL tree.
*/
AVLTree(const AVLTree& other);
AVLTree& operator= (const AVLTree& other);
/**
* Type: iterator
* Type: const_iterator
* -------------------------------------------------------------------------
* A pair of types that can traverse the elements of an AVL tree in
* ascending order.
*/
class iterator;
class const_iterator;
/**
* Type: reverse_iterator
* Type: const_reverse_iterator
* -------------------------------------------------------------------------
* A pair of types that can traverse the elements of an AVL tree in
* descending order.
*/
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
/**
* std::pair<iterator, bool> insert(const Key& key, const Value& value);
* Usage: myAVLTree.insert("Skiplist", 137);
* -------------------------------------------------------------------------
* Inserts the specified key/value pair into the AVL tree. If an entry with
* the specified key already existed, this function returns false paired
* with an iterator to the extant value. If the entry was inserted
* successfully, returns true paired with an iterator to the new element.
*/
std::pair<iterator, bool> insert(const Key& key, const Value& value);
/**
* bool erase(const Key& key);
* Usage: myAVLTree.erase("AVL Tree");
* -------------------------------------------------------------------------
* Removes the entry from the AVL tree with the specified key, if it exists.
* Returns whether or not an element was erased. All outstanding iterators
* remain valid, except for those referencing the deleted element.
*/
bool erase(const Key& key);
/**
* iterator erase(iterator where);
* Usage: myAVLTree.erase(myAVLTree.begin());
* -------------------------------------------------------------------------
* Removes the entry referenced by the specified iterator from the tree,
* returning an iterator to the next element in the sequence.
*/
iterator erase(iterator where);
/**
* iterator find(const Key& key);
* const_iterator find(const Key& key);
* Usage: if (myAVLTree.find("Skiplist") != myAVLTree.end()) { ... }
* -------------------------------------------------------------------------
* Returns an iterator to the entry in the AVL tree with the specified key,
* or end() as as sentinel if it does not exist.
*/
iterator find(const Key& key);
const_iterator find(const Key& key) const;
/**
* Value& operator[] (const Key& key);
* Usage: myAVLTree["skiplist"] = 137;
* -------------------------------------------------------------------------
* Returns a reference to the value associated with the specified key in the
* AVL tree. If the key is not contained in the AVL tree, it will be
* inserted into the AVL tree with a default-constructed Entry as its value.
*/
Value& operator[] (const Key& key);
/**
* Value& at(const Key& key);
* const Value& at(const Key& key) const;
* Usage: myAVLTree.at("skiplist") = 137;
* -------------------------------------------------------------------------
* Returns a reference to the value associated with the specified key,
* throwing a std::out_of_range exception if the key does not exist in the
* AVL tree.
*/
Value& at(const Key& key);
const Value& at(const Key& key) const;
/**
* (const_)iterator begin() (const);
* (const_)iterator end() (const);
* Usage: for (AVLTree<string, int>::iterator itr = t.begin();
* itr != t.end(); ++itr) { ... }
* -------------------------------------------------------------------------
* Returns iterators delineating the full contents of the AVL tree. Each
* iterator acts as a pointer to a std::pair<const Key, Entry>.
*/
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
/**
* (const_)reverse_iterator rbegin() (const);
* (const_)reverse_iterator rend() (const);
* Usage: for (AVLTree<string, int>::reverse_iterator itr = s.rbegin();
* itr != s.rend(); ++itr) { ... }
* -------------------------------------------------------------------------
* Returns iterators delineating the full contents of the AVL tree in
* reverse order.
*/
reverse_iterator rbegin();
reverse_iterator rend();
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
/**
* (const_)iterator lower_bound(const Key& key) (const);
* (const_)iterator upper_bound(const Key& key) (const);
* Usage: for (AVLTree<string, int>::iterator itr = t.lower_bound("AVL");
* itr != t.upper_bound("skiplist"); ++itr) { ... }
* -------------------------------------------------------------------------
* lower_bound returns an iterator to the first element in the AVL tree
* whose key is at least as large as key. upper_bound returns an iterator
* to the first element in the AVL tree whose key is strictly greater than
* key.
*/
iterator lower_bound(const Key& key);
iterator upper_bound(const Key& key);
const_iterator lower_bound(const Key& key) const;
const_iterator upper_bound(const Key& key) const;
/**
* std::pair<(const_)iterator, (const_)iterator>
* equal_range(const Key& key) (const);
* Usage: std::pair<AVLTree<int, int>::iterator, AVLTree<int, int>::iterator>
* range = t.equal_range("AVL");
* -------------------------------------------------------------------------
* Returns a range of iterators spanning the unique copy of the entry whose
* key is key if it exists, and otherwise a pair of iterators both pointing
* to the spot in the AVL tree where the element would be if it were.
*/
std::pair<iterator, iterator> equal_range(const Key& key);
std::pair<const_iterator, const_iterator> equal_range(const Key& key) const;
/**
* size_t size() const;
* Usage: cout << "AVLTree contains " << s.size() << " entries." << endl;
* -------------------------------------------------------------------------
* Returns the number of elements stored in the AVL tree.
*/
size_t size() const;
/**
* bool empty() const;
* Usage: if (s.empty()) { ... }
* -------------------------------------------------------------------------
* Returns whether the AVL tree contains no elements.
*/
bool empty() const;
/**
* void swap(AVLTree& other);
* Usage: one.swap(two);
* -------------------------------------------------------------------------
* Exchanges the contents of this AVL tree and some other AVL tree. All
* outstanding iterators are invalidated.
*/
void swap(AVLTree& other);
private:
/* A type representing a node in the AVL tree. */
struct Node {
std::pair<const Key, Value> mValue; // The actual value stored here
/* The children are stored in an array to make it easier to implement tree
* rotations. The first entry is the left child, the second the right.
*/
Node* mChildren[2];
/* Pointer to the parent node. */
Node* mParent;
/* Pointer to the next and previous node in the sorted sequence. */
Node* mNext, *mPrev;
/* The height of this node, which is stored as an integer to make
* subtraction easier.
*/
int mHeight;
/* Constructor sets up the value to the specified key/value pair with the
* specified height.
*/
Node(const Key& key, const Value& value, int height);
};
/* A pointer to the first and last elements of the AVL tree. */
Node* mHead, *mTail;
/* A pointer to the root of the tree. */
Node* mRoot;
/* The comparator to use when storing elements. */
Comparator mComp;
/* The number of elements in the list. */
size_t mSize;
/* A utility base class for iterator and const_iterator which actually
* supplies all of the logic necessary for the two to work together. The
* parameters are the derived type, the type of a pointer being visited, and
* the type of a reference being visited. This uses the Curiously-Recurring
* Template Pattern to work correctly.
*/
template <typename DerivedType, typename Pointer, typename Reference>
class IteratorBase;
template <typename DerivedType, typename Pointer, typename Reference>
friend class IteratorBase;
/* Make iterator and const_iterator friends as well so they can use the
* Node type.
*/
friend class iterator;
friend class const_iterator;
/* A utility function to perform a tree rotation to pull the child above its
* parent. This function is semantically const but not bitwise const, since
* it changes the structure but not the content of the elements being
* stored.
*/
void rotateUp(Node* child);
/* A utility function that, given a node, returns the height of that node.
* If the node is NULL, 0 is returned.
*/
static int height(const Node* node);
/* A utility function that, given a node, returns its balance factor. */
static int balanceFactor(const Node* node);
/* A utility function which does a BST search on the tree, looking for the
* indicated node. The return result is a pair of pointers, the first of
* which is the node being searched for, or NULL if that node is not found.
* The second node is that node's parent, which is either the parent of the
* found node, or the last node visited in the tree before NULL was found
* if the node was not found.
*/
std::pair<Node*, Node*> findNode(const Key& key) const;
/* A utility function which walks up from the indicated node up to the root,
* performing the tree rotations necessary to restore the balances in the
* tree.
*/
void rebalanceFrom(Node* where);
/* A utility function which, given a node with at most one child, splices
* that node out of the tree by replacing it with its one child. The next
* and previous pointers of that node are not modified, since this function
* can be used to structurally remove nodes from the tree while remembering
* where they are in sorted order.
*/
void spliceOut(Node* where);
/* A utility function which, given a node and the node to use as its parent,
* recursively deep-copies the tree rooted at that node, using the parent
* node as the new tree's parent.
*/
static Node* cloneTree(Node* toClone, Node* parent);
/* A utility function which, given a tree and a pointer to the predecessor
* of that tree, rewires the linked list in that tree to represent an
* inorder traversal. No fields are modified. The return value is the node
* with the highest key.
*/
static Node* rethreadLinkedList(Node* root, Node* predecessor);
};
/* Comparison operators for AVLTrees. */
template <typename Key, typename Value, typename Comparator>
bool operator< (const AVLTree<Key, Value, Comparator>& lhs,
const AVLTree<Key, Value, Comparator>& rhs);
template <typename Key, typename Value, typename Comparator>
bool operator<= (const AVLTree<Key, Value, Comparator>& lhs,
const AVLTree<Key, Value, Comparator>& rhs);
template <typename Key, typename Value, typename Comparator>
bool operator== (const AVLTree<Key, Value, Comparator>& lhs,
const AVLTree<Key, Value, Comparator>& rhs);
template <typename Key, typename Value, typename Comparator>
bool operator!= (const AVLTree<Key, Value, Comparator>& lhs,
const AVLTree<Key, Value, Comparator>& rhs);
template <typename Key, typename Value, typename Comparator>
bool operator>= (const AVLTree<Key, Value, Comparator>& lhs,
const AVLTree<Key, Value, Comparator>& rhs);
template <typename Key, typename Value, typename Comparator>
bool operator> (const AVLTree<Key, Value, Comparator>& lhs,
const AVLTree<Key, Value, Comparator>& rhs);
/* * * * * Implementation Below This Point * * * * */
/* Definition of the IteratorBase type, which is used to provide a common
* implementation for iterator and const_iterator.
*/
template <typename Key, typename Value, typename Comparator>
template <typename DerivedType, typename Pointer, typename Reference>
class AVLTree<Key, Value, Comparator>::IteratorBase {
public:
/* Utility typedef to talk about nodes. */
typedef typename AVLTree<Key, Value, Comparator>::Node Node;
/* Advance operators just construct derived type instances of the proper
* type, then advance them.
*/
DerivedType& operator++ () {
mCurr = mCurr->mNext;
/* Downcast to our actual type. */
return static_cast<DerivedType&>(*this);
}
const DerivedType operator++ (int) {
/* Copy our current value by downcasting to our real type. */
DerivedType result = static_cast<DerivedType&>(*this);
/* Advance to the next element. */
++*this;
/* Hand back the cached value. */
return result;
}
/* Backup operators work on the same principle. */
DerivedType& operator-- () {
/* If the current pointer is NULL, it means that we've walked off the end
* of the structure and need to back up a step.
*/
if (mCurr == NULL) {
mCurr = mOwner->mTail;
}
/* Otherwise, just back up a step. */
else {
mCurr = mCurr->mPrev;
}
/* Downcast to our actual type. */
return static_cast<DerivedType&>(*this);
}
const DerivedType operator-- (int) {
/* Copy our current value by downcasting to our real type. */
DerivedType result = static_cast<DerivedType&>(*this);
/* Back up a step. */
--*this;
/* Hand back the cached value. */
return result;
}
/* Equality and disequality operators are parameterized - we'll allow anyone
* whose type is IteratorBase to compare with us. This means that we can
* compare both iterator and const_iterator against one another.
*/
template <typename DerivedType2, typename Pointer2, typename Reference2>
bool operator== (const IteratorBase<DerivedType2, Pointer2, Reference2>& rhs) {
/* Just check the underlying pointers, which (fortunately!) are of the
* same type.
*/
return mOwner == rhs.mOwner && mCurr == rhs.mCurr;
}
template <typename DerivedType2, typename Pointer2, typename Reference2>
bool operator!= (const IteratorBase<DerivedType2, Pointer2, Reference2>& rhs) {
/* We are disequal if equality returns false. */
return !(*this == rhs);
}
/* Pointer dereference operator hands back a reference. */
Reference operator* () const {
return mCurr->mValue;
}
/* Arrow operator returns a pointer. */
Pointer operator-> () const {
/* Use the standard "&**this" trick to dereference this object and return
* a pointer to the referenced value.
*/
return &**this;
}
protected:
/* Which AVLTree we belong to. This pointer is const even though we are
* possibly allowing ourselves to modify the AVL tree elements to avoid having
* to duplicate this logic once again for const vs. non-const iterators.
*/
const AVLTree* mOwner;
/* Where we are in the list. */
Node* mCurr;
/* In order for equality comparisons to work correctly, all IteratorBases
* must be friends of one another.
*/
template <typename Derived2, typename Pointer2, typename Reference2>
friend class IteratorBase;
/* Constructor sets up the AVL tree and node pointers appropriately. */
IteratorBase(const AVLTree* owner = NULL, Node* curr = NULL)
: mOwner(owner), mCurr(curr) {
// Handled in initializer list
}
};
/* iterator and const_iterator implementations work by deriving off of
* IteratorBase, passing in parameters that make all the operators work.
* Additionally, we inherit from std::iterator to import all the necessary
* typedefs to qualify as an iterator.
*/
template <typename Key, typename Value, typename Comparator>
class AVLTree<Key, Value, Comparator>::iterator:
public std::iterator< std::bidirectional_iterator_tag,
std::pair<const Key, Value> >,
public IteratorBase<iterator, // Our type
std::pair<const Key, Value>*, // Reference type
std::pair<const Key, Value>&> { // Pointer type
public:
/* Default constructor forwards NULL to base implicity. */
iterator() {
// Nothing to do here.
}
/* All major operations inherited from the base type. */
private:
/* Constructor for creating an iterator out of a raw node just forwards this
* argument to the base type. This line is absolutely awful because the
* type of the base is so complex.
*/
iterator(const AVLTree* owner,
typename AVLTree<Key, Value, Comparator>::Node* node) :
IteratorBase<iterator,
std::pair<const Key, Value>*,
std::pair<const Key, Value>&>(owner, node) {
// Handled by initializer list
}
/* Make the AVLTree a friend so it can call this constructor. */
friend class AVLTree;
/* Make const_iterator a friend so we can do iterator-to-const_iterator
* conversions.
*/
friend class const_iterator;
};
/* Same as above, but with const added in. */
template <typename Key, typename Value, typename Comparator>
class AVLTree<Key, Value, Comparator>::const_iterator:
public std::iterator< std::bidirectional_iterator_tag,
const std::pair<const Key, Value> >,
public IteratorBase<const_iterator, // Our type
const std::pair<const Key, Value>*, // Reference type
const std::pair<const Key, Value>&> { // Pointer type
public:
/* Default constructor forwards NULL to base implicity. */
const_iterator() {
// Nothing to do here.
}
/* iterator conversion constructor forwards the other iterator's base fields
* to the base class.
*/
const_iterator(iterator itr) :
IteratorBase<const_iterator,
const std::pair<const Key, Value>*,
const std::pair<const Key, Value>&>(itr.mOwner, itr.mCurr) {
// Handled in initializer list
}
/* All major operations inherited from the base type. */
private:
/* See iterator implementation for details about what this does. */
const_iterator(const AVLTree* owner,
typename AVLTree<Key, Value, Comparator>::Node* node) :
IteratorBase<const_iterator,
const std::pair<const Key, Value>*,
const std::pair<const Key, Value>&>(owner, node) {
// Handled by initializer list
}
/* Make the AVLTree a friend so it can call this constructor. */
friend class AVLTree;
};
/**** AVLTree::Node Implementation. ****/
/* Constructor sets up the key and value, then sets the height to one. The
* linked list fields are left uninitialized.
*/
template <typename Key, typename Value, typename Comparator>
AVLTree<Key, Value, Comparator>::Node::Node(const Key& key,
const Value& value,
int height)
: mValue(key, value), mHeight(height) {
// Handled in initializer list.
}
/**** AVLTree Implementation ****/
/* Constructor sets up a new, empty AVLTree. */
template <typename Key, typename Value, typename Comparator>
AVLTree<Key, Value, Comparator>::AVLTree(Comparator comp) : mComp(comp) {
/* Initially, the list of elements is empty and the tree is NULL. */
mHead = mTail = mRoot = NULL;
/* The tree is created empty. */
mSize = 0;
}
/* Destructor walks the linked list of elements, deleting all nodes it
* encounters.
*/
template <typename Key, typename Value, typename Comparator>
AVLTree<Key, Value, Comparator>::~AVLTree() {
/* Start at the head of the list. */
Node* curr = mHead;
while (curr != NULL) {
/* Cache the next value; we're about to blow up our only pointer to it. */
Node* next = curr->mNext;
/* Free memory, then go to the next node. */
delete curr;
curr = next;
}
}
/* Inserting a node works by walking down the tree until the insert point is
* found, adding the value, then fixing up the balance factors on each node.
*/
template <typename Key, typename Value, typename Comparator>
std::pair<typename AVLTree<Key, Value, Comparator>::iterator, bool>
AVLTree<Key, Value, Comparator>::insert(const Key& key, const Value& value) {
/* Recursively walk down the tree from the root, looking for where the value
* should go. In the course of doing so, we'll maintain some extra
* information about the node's successor and predecessor so that we can
* wire the new node in in O(1) time.
*
* The information that we'll need will be the last nodes at which we
* visited the left and right child. This is because if the new node ends
* up as a left child, then its predecessor is the last ancestor on the path
* where we followed its right pointer, and vice-versa if the node ends up
* as a right child.
*/
Node* lastLeft = NULL, *lastRight = NULL;
/* Also keep track of our current location as a pointer to the pointer in
* the tree where the node will end up, which allows us to insert the node
* by simply rewiring this pointer.
*/
Node** curr = &mRoot;
/* Also track the last visited node. */
Node* parent = NULL;
/* Now, do a standard binary tree insert. If we ever find the node, we can
* stop early.
*/
while (*curr != NULL) {
/* Update the parent to be this node, since it's the last one visited. */
parent = *curr;
/* Check whether we belong in the left subtree. */
if (mComp(key, (*curr)->mValue.first)) {
lastLeft = *curr;
curr = &(*curr)->mChildren[0];
}
/* ... or perhaps the right subtree. */
else if (mComp((*curr)->mValue.first, key)) {
lastRight = *curr; // Last visited node where we went right.
curr = &(*curr)->mChildren[1];
}
/* Otherwise, the key must already exist in the tree. Return a pointer to
* it.
*/
else
return std::make_pair(iterator(this, *curr), false);
}
/* At this point we've found our insertion point and can create the node
* we're going to wire in. Initially, it's at height 1.
*/
Node* toInsert = new Node(key, value, 1);
/* Splice it into the tree. */
toInsert->mParent = parent;
*curr = toInsert;
/* The new node has no children. */
toInsert->mChildren[0] = toInsert->mChildren[1] = NULL;
/* Wire this node into the linked list in-between its predecessor and
* successor in the tree. The successor is the last node where we went
* left, and the predecessor is the last node where we went right.
*/
toInsert->mNext = lastLeft;
toInsert->mPrev = lastRight;
/* Update the previous pointer of the next entry, or change the list tail
* if there is no next entry.
*/
if (toInsert->mNext)
toInsert->mNext->mPrev = toInsert;
else
mTail = toInsert;
/* Update the next pointer of the previous entry similarly. */
if (toInsert->mPrev)
toInsert->mPrev->mNext = toInsert;
else
mHead = toInsert;
/* Rebalance the tree from this node upward. */
rebalanceFrom(toInsert);
/* Increase the size of the tree, since we just added a node. */
++mSize;
/* Hand back an iterator to the new element, along with a notification that
* it was inserted correctly.
*/
return std::make_pair(iterator(this, toInsert), true);
}
/* To perform a tree rotation, we identify whether we're doing a left or
* right rotation, then rewrite pointers as follows:
*
* In a right rotation, we do the following:
*
* B A
* / \ / \
* A 2 --> 0 B
* / \ / \
* 0 1 1 2
*
* In a left rotation, this runs backwards.
*
* The reason that we've implemented the nodes as an array of pointers rather
* than using two named pointers is that the logic is symmetric. If the node
* is its left child, then its parent becomes its right child, and the node's
* right child becomes the parent's left child. If the node is its parent's
* right child, then the node's parent becomes its left child and the node's
* left child becomes the parent's right child. In other words, the general
* formula is
*
* If the node is its parent's SIDE child, then the parent becomes that node's
* OPPOSITE-SIDE child, and the node's OPPOSITE-SIDE child becomes the
* parent's SIDE child.
*
* This code also updates the root if the tree root gets rotated out. It also
* ensures that the heights of the rotated nodes are properly adjusted.
*/
template <typename Key, typename Value, typename Comparator>
void AVLTree<Key, Value, Comparator>::rotateUp(Node* node) {
/* Determine which side the node is on. It's on the left (side 0) if the
* parent's first pointer matches it, and is on the right (side 1) if the
* node's first pointer doesn't match it. This is, coincidentally, whether
* the node is not equal to the first pointer of its root.
*/
const int side = (node != node->mParent->mChildren[0]);
/* The other side is the logical negation of the side itself. */
const int otherSide = !side;
/* Cache the displaced child and parent of the current node. */
Node* child = node->mChildren[otherSide];
Node* parent = node->mParent;
/* Shuffle pointers around to make the node the parent of its parent. */
node->mParent = parent->mParent;
node->mChildren[otherSide] = parent;
/* Shuffle around pointers so that the parent takes on the displaced
* child.
*/
parent->mChildren[side] = child;
if (child)
child->mParent = parent;
/* Update the grandparent (if any) so that its child is now the rotated
* element rather than the parent. If there is no grandparent, the node is
* now the root.
*/
if (parent->mParent) {
const int parentSide = (parent != parent->mParent->mChildren[0]);
parent->mParent->mChildren[parentSide] = node;
} else
mRoot = node;
/* In either case, change the parent so that it now treats the node as the
* parent.
*/
parent->mParent = node;
/* Change the heights of the nodes. Each node is now at a height one
* greater than the max height of its children. We recompute the parent's
* height first to ensure that any changes to it propagate correctly.
*/
parent->mHeight = 1 + std::max(height(parent->mChildren[0]),
height(parent->mChildren[1]));
node->mHeight = 1 + std::max(height(node->mChildren[0]),
height(node->mChildren[1]));
}
/* To determine the height of a node, we just hand back the node's recorded
* height, or 0 if the node is NULL.
*/
template <typename Key, typename Value, typename Comparator>
int AVLTree<Key, Value, Comparator>::height(const Node* node) {
return node? node->mHeight : 0;
}
/* Computing the balance factor just computes the difference in heights
* between a node's left and right children.
*/
template <typename Key, typename Value, typename Comparator>
int AVLTree<Key, Value, Comparator>::balanceFactor(const Node* node) {
return height(node->mChildren[0]) - height(node->mChildren[1]);
}
/* Implementation of the logic for rebalancing the AVL tree via a series of
* rotations. This code computes the balance factor at each node and makes
* one of the following two rotations if the balance is either +2 or -2:
*
* 1. If the child on the tall side has a balance factor whose sign isn't the
* opposite of the real node's balance factor, perform a single rotation
* from that child.
* 2. If the child on the tall side has a balance factor whose sign is the
* opposite of the real node's balance factor, rotate its child on its
* tall side upward, then rotate it again with the original node.
*/
template <typename Key, typename Value, typename Comparator>
void AVLTree<Key, Value, Comparator>::rebalanceFrom(Node* where) {
/* Start walking up from the node toward the root, checking for any new
* imbalances and recomputing heights as appropriate.
*/
while (where != NULL) {
/* Recompute the height of this node. */
where->mHeight = 1 + std::max(height(where->mChildren[0]),
height(where->mChildren[1]));
/* Get the balance factor. */
const int balance = balanceFactor(where);
/* If the balance factor is +/- 2, we need to do some rotations. */
if (balance == 2 || balance == -2) {
/* Determine what child is on the heavy side. If the balance is +2,
* this is the left child (child 0), and if it's -2 it's the right child
* (child 1). We use the comparison balance == -2 for this, since its
* values match what we need in this case.
*/
Node* tallChild = where->mChildren[balance == -2];
/* Check its balance factor and see what kind of rotation we need. */
const int childBalance = balanceFactor(tallChild);
/* We do a single rotation unless the child node is balanced opposite of
* its parent.
*/
if (childBalance == 0 || (childBalance < 0) == (balance < 0)) {
rotateUp(tallChild);
/* This node is now balanced, but we still need to update heights up
* elsewhere in the tree. Set the search to continue from the parent
* of this node.
*/
where = tallChild->mParent;
}
/* Otherwise, we need to do a double rotation. */
else {
/* We need a slightly different test to determine what child is heavy
* since the balance is going to be +1 or -1 in this case.
*/
Node* tallGrandchild = tallChild->mChildren[childBalance == -1];
/* Rotate this node up twice. */
rotateUp(tallGrandchild);
rotateUp(tallGrandchild);