TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
tree_234.cpp
Go to the documentation of this file.
1
16#include <array>
17#include <cassert>
18#include <fstream>
19#include <iostream>
20#include <memory>
21#include <queue>
22#include <string>
23
28namespace data_structures {
33namespace tree_234 {
35class Node {
36 public:
41 explicit Node(int64_t item)
42 : count(1),
43 items({{item, 0, 0}}),
44 children({{nullptr, nullptr, nullptr, nullptr}}) {}
45
50 int8_t GetCount() { return count; }
51
61 void SetCount(int8_t c) { count = c; }
62
67 bool IsLeaf() { return children[0] == nullptr; }
68
73 bool IsFull() { return count == 3; }
74
79 bool Is2Node() { return count == 1; }
80
85 bool Is34Node() { return count == 2 || count == 3; }
86
92 bool Contains(int64_t item) {
93 for (int8_t i = 0; i < count; i++) {
94 if (item == items[i]) {
95 return true;
96 }
97 }
98 return false;
99 }
100
107 int8_t GetItemIndex(int64_t item) {
108 for (int8_t i = 0; i < count; i++) {
109 if (items[i] == item) {
110 return i;
111 }
112 }
113 return -1;
114 }
115
120 int64_t GetMaxItem() { return items[count - 1]; }
121
126 int64_t GetMinItem() { return items[0]; }
127
133 int64_t GetItem(int8_t index) { return items[index]; }
134
140 void SetItem(int8_t index, int64_t new_item) {
141 assert(index >= 0 && index <= 2);
142
143 items[index] = new_item;
144 }
145
163 int InsertItem(int item) {
164 assert(!IsFull());
165
166 if (Contains(item)) {
167 return -1;
168 }
169
170 int8_t i = 0;
171 for (i = 0; i < count; i++) {
172 if (items[i] > item) {
173 break;
174 }
175 }
176
177 InsertItemByIndex(i, item, nullptr, true);
178 return i;
179 }
180
189 void InsertItemByIndex(int8_t index, int64_t item, Node *with_child,
190 bool to_left = true) {
191 assert(count < 3 && index >= 0 && index < 3);
192
193 for (int8_t i = count - 1; i >= index; i--) {
194 items[i + 1] = items[i];
195 }
196
197 items[index] = item;
198
199 int8_t start_index = to_left ? index : index + 1;
200
201 for (int8_t i = count; i >= start_index; i--) {
202 children[i + 1] = children[i];
203 }
204
205 children[start_index] = with_child;
206
207 count++;
208 }
209
217 Node *RemoveItemByIndex(int8_t index, bool keep_left) {
218 assert(index >= 0 && index < count);
219 Node *removed_child = keep_left ? children[index + 1] : children[index];
220 for (int8_t i = index; i < count - 1; i++) {
221 items[i] = items[i + 1];
222 }
223
224 for (int8_t i = keep_left ? index + 1 : index; i < count; i++) {
225 children[i] = children[i + 1];
226 }
227
228 count--;
229 return removed_child;
230 }
231
237 int8_t GetChildIndex(Node *child) {
238 for (int8_t i = 0; i < count + 1; i++) {
239 if (children[i] == child) {
240 return i;
241 }
242 }
243
244 return -1;
245 }
246
252 Node *GetChild(int8_t index) { return children[index]; }
253
259 void SetChild(int8_t index, Node *child) { children[index] = child; }
260
266
272
278 Node *GetItemLeftChild(int8_t item_index) {
279 if (item_index < 0 || item_index > count - 1) {
280 return nullptr;
281 }
282
283 return children[item_index];
284 }
285
291 Node *GetItemRightChild(int8_t item_index) {
292 if (item_index < 0 || item_index > count - 1) {
293 return nullptr;
294 }
295
296 return children[item_index + 1];
297 }
298
304 Node *GetNextPossibleChild(int64_t item) {
305 int i = 0;
306 for (i = 0; i < count; i++) {
307 if (items[i] > item) {
308 break;
309 }
310 }
311 return children[i];
312 }
313
314 private:
315 std::array<int64_t, 3> items;
316
317 std::array<Node *, 4> children;
318
319 int8_t count = 0;
320};
321
323class Tree234 {
324 public:
325 Tree234() = default;
326 Tree234(const Tree234 &) = delete;
327 Tree234(const Tree234 &&) = delete;
328 Tree234 &operator=(const Tree234 &) = delete;
329 Tree234 &operator=(const Tree234 &&) = delete;
330
331 ~Tree234();
332
337 void Insert(int64_t item);
338
344 bool Remove(int64_t item);
345
347 void Traverse();
348
354 void Print(const char *file_name = nullptr);
355
356 private:
361 void InsertPreSplit(int64_t item);
362
367 void InsertPostMerge(int64_t item);
368
375 Node *Insert(Node *tree, int64_t item);
376
390 Node *MergeNode(Node *dst_node, Node *node);
391
402 void MergeNodeNotFull(Node *dst_node, Node *node);
403
411
417 int64_t GetTreeMaxItem(Node *tree);
418
424 int64_t GetTreeMinItem(Node *tree);
425
441 bool TryLeftRotate(Node *parent, Node *to_child);
442
458 bool TryRightRotate(Node *parent, Node *to_child);
459
472 void RightRotate(Node *parent, int8_t index);
473
485 void LeftRotate(Node *parent, int8_t index);
486
493 bool RemovePreMerge(Node *node, int64_t item);
494
508 Node *Merge(Node *parent, int8_t index);
509
514 void DeleteNode(Node *tree);
515
520 void Traverse(Node *tree);
521
535 void PrintNode(std::ofstream &ofs, Node *node, int64_t parent_index,
536 int64_t index, int8_t parent_child_index);
537
538 Node *root_{nullptr};
539};
540
541Tree234::~Tree234() { DeleteNode(root_); }
542
548 if (!tree) {
549 return;
550 }
551 for (int8_t i = 0; i <= tree->GetCount(); i++) {
552 DeleteNode(tree->GetChild(i));
553 }
554
555 delete tree;
556}
557
564 std::cout << std::endl;
565}
566
568 if (!node) {
569 return;
570 }
571
572 int8_t i = 0;
573 for (i = 0; i < node->GetCount(); i++) {
574 Traverse(node->GetChild(i));
575 std::cout << node->GetItem(i) << ", ";
576 }
577
578 Traverse(node->GetChild(i));
579}
580
585void Tree234::InsertPreSplit(int64_t item) {
586 if (!root_) {
587 root_ = new Node(item);
588 return;
589 }
590
591 Node *parent = nullptr;
592 Node *node = root_;
593
594 while (true) {
595 if (!node) {
596 std::unique_ptr<Node> tmp(new Node(item));
597 MergeNodeNotFull(parent, tmp.get());
598 return;
599 }
600
601 if (node->Contains(item)) {
602 return;
603 }
604
605 if (node->IsFull()) {
607
608 Node *cur_node = nullptr;
609
610 if (item < node->GetItem(0)) {
611 cur_node = node->GetChild(0);
612 } else {
613 cur_node = node->GetChild(1);
614 }
615
616 if (!parent) {
617 // for the root node parent is nullptr, we simply assign the
618 // split parent to root_
619 root_ = node;
620 } else {
621 // merge the split parent to its origin parent
622 MergeNodeNotFull(parent, node);
623 }
624
625 node = cur_node;
626 }
627
628 parent = node;
629 node = parent->GetNextPossibleChild(item);
630 }
631}
632
637void Tree234::InsertPostMerge(int64_t item) {
638 if (!root_) {
639 root_ = new Node(item);
640 return;
641 }
642
643 Node *split_node = Insert(root_, item);
644
645 // if root has split, then update root_
646 if (split_node) {
647 root_ = split_node;
648 }
649}
650
655void Tree234::Insert(int64_t item) { InsertPreSplit(item); }
656
663Node *Tree234::Insert(Node *tree, int64_t item) {
664 assert(tree != nullptr);
665
666 std::unique_ptr<Node> split_node;
667
668 if (tree->Contains(item)) {
669 // return nullptr indicate current node not overflow
670 return nullptr;
671 }
672
673 Node *next_node = tree->GetNextPossibleChild(item);
674 if (next_node) {
675 split_node.reset(Insert(next_node, item));
676 } else {
677 split_node.reset(new Node(item));
678 }
679
680 if (split_node) {
681 return MergeNode(tree, split_node.get());
682 }
683
684 return nullptr;
685}
686
701 assert(dst_node != nullptr && node != nullptr);
702
703 if (!dst_node->IsFull()) {
704 MergeNodeNotFull(dst_node, node);
705 return nullptr;
706 }
707
708 dst_node = SplitNode(dst_node);
709
710 if (node->GetItem(0) < dst_node->GetItem(0)) {
711 MergeNodeNotFull(dst_node->GetChild(0), node);
712
713 } else {
714 MergeNodeNotFull(dst_node->GetChild(1), node);
715 }
716
717 return dst_node;
718}
719
731 assert(dst_node && node && !dst_node->IsFull() && node->Is2Node());
732
733 int8_t i = dst_node->InsertItem(node->GetItem(0));
734
735 dst_node->SetChild(i, node->GetChild(0));
736 dst_node->SetChild(i + 1, node->GetChild(1));
737}
738
746 assert(node->GetCount() == 3);
747
748 Node *left = node;
749
750 Node *right = new Node(node->GetItem(2));
751 right->SetChild(0, node->GetChild(2));
752 right->SetChild(1, node->GetChild(3));
753
754 Node *parent = new Node(node->GetItem(1));
755 parent->SetChild(0, left);
756 parent->SetChild(1, right);
757
758 left->SetCount(1);
759
760 return parent;
761}
762
778bool Tree234::TryLeftRotate(Node *parent, Node *to_child) {
779 int to_child_index = parent->GetChildIndex(to_child);
780
781 // child is right most, can not do left rotate to it
782 if (to_child_index >= parent->GetCount()) {
783 return false;
784 }
785
786 Node *right_sibling = parent->GetChild(to_child_index + 1);
787
788 // right sibling is 2-node. can not do left rotate.
789 if (right_sibling->Is2Node()) {
790 return false;
791 }
792
793 LeftRotate(parent, to_child_index);
794
795 return true;
796}
797
813bool Tree234::TryRightRotate(Node *parent, Node *to_child) {
814 int8_t to_child_index = parent->GetChildIndex(to_child);
815
816 // child is left most, can not do right rotate to it
817 if (to_child_index <= 0) {
818 return false;
819 }
820
821 Node *left_sibling = parent->GetChild(to_child_index - 1);
822
823 // right sibling is 2-node. can not do left rotate.
824 if (left_sibling->Is2Node()) {
825 return false;
826 }
827
828 RightRotate(parent, to_child_index - 1);
829
830 return true;
831}
832
845void Tree234::RightRotate(Node *parent, int8_t index) {
846 Node *left = parent->GetItemLeftChild(index);
847 Node *right = parent->GetItemRightChild(index);
848
849 assert(left && left->Is34Node());
850 assert(right && right->Is2Node());
851
852 right->InsertItemByIndex(0, parent->GetItem(index),
853 left->GetRightmostChild(), true);
854 parent->SetItem(index, left->GetMaxItem());
855 left->RemoveItemByIndex(left->GetCount() - 1, true);
856}
857
869void Tree234::LeftRotate(Node *parent, int8_t index) {
870 Node *left = parent->GetItemLeftChild(index);
871 Node *right = parent->GetItemRightChild(index);
872
873 assert(right && right->Is34Node());
874 assert(left && left->Is2Node());
875
876 left->InsertItemByIndex(left->GetCount(), parent->GetItem(index),
877 right->GetLeftmostChild(), false);
878 parent->SetItem(index, right->GetMinItem());
879 right->RemoveItemByIndex(0, false);
880}
881
895Node *Tree234::Merge(Node *parent, int8_t index) {
896 assert(parent);
897
898 // bool is_parent_2node = parent->Is2Node();
899
900 Node *left_child = parent->GetItemLeftChild(index);
901 Node *right_child = parent->GetItemRightChild(index);
902
903 assert(left_child->Is2Node() && right_child->Is2Node());
904
905 int64_t item = parent->GetItem(index);
906
907 // 1. merge parent's item and right child to left child
908 left_child->SetItem(1, item);
909 left_child->SetItem(2, right_child->GetItem(0));
910 left_child->SetChild(2, right_child->GetChild(0));
911 left_child->SetChild(3, right_child->GetChild(1));
912
913 left_child->SetCount(3);
914
915 // 2. remove the parent's item
916 parent->RemoveItemByIndex(index, true);
917
918 // 3. delete the unused right child
919 delete right_child;
920
921 return left_child;
922}
923
929bool Tree234::Remove(int64_t item) { return RemovePreMerge(root_, item); }
930
937bool Tree234::RemovePreMerge(Node *node, int64_t item) {
938 while (node) {
939 if (node->IsLeaf()) {
940 if (node->Contains(item)) {
941 if (node->Is2Node()) {
942 // node must be root
943 delete node;
944 root_ = nullptr;
945 } else {
946 node->RemoveItemByIndex(node->GetItemIndex(item), true);
947 }
948 return true;
949 }
950 return false;
951 }
952
953 // node is internal
954 if (node->Contains(item)) {
955 int8_t index = node->GetItemIndex(item);
956
957 // Here is important!!! What we do next depend on its children's
958 // state. Why?
959 Node *left_child = node->GetItemLeftChild(index);
960 Node *right_child = node->GetItemRightChild(index);
961 assert(left_child && right_child);
962
963 if (left_child->Is2Node() && right_child->Is2Node()) {
964 // both left and right child are 2-node,we should not modify
965 // current node in this situation. Because we are going to do
966 // merge with its children which will move target item to next
967 // layer. so if we replace the item with successor or
968 // predecessor now, when we do the recursive remove with
969 // successor or predecessor, we will result in removing the just
970 // replaced one in the merged node. That's not what we want.
971
972 // we need to convert the child 2-node to 3-node or 4-node
973 // first. First we try to see if any of them can convert to
974 // 3-node by rotate. By using rotate we keep the empty house for
975 // the future insertion which will be more efficient than merge.
976 //
977 // | ? | node | ? |
978 // / | | \
979 // / | | \
980 // / | | \
981 // / | | \
982 // / | | \
983 // / | | \
984 // ? left_child right_child ?
985 //
986
987 // node must be the root
988 if (node->Is2Node()) {
989 // this means we can't avoid merging the target item into
990 // next layer, and this will cause us do different process
991 // compared with other cases
992 Node *new_root = Merge(node, index);
993 delete root_;
994 root_ = new_root;
995 node = root_;
996
997 // now node point to the
998 continue;
999 }
1000
1001 // here means we can avoid merging the target item into next
1002 // layer. So we convert one of its left or right child to 3-node
1003 // and then do the successor or predecessor swap and recursive
1004 // remove the next layer will successor or predecessor.
1005 do {
1006 if (index > 0) {
1007 // left_child has left-sibling, we check if we can do a
1008 // rotate
1009 Node *left_sibling = node->GetItemLeftChild(index - 1);
1010 if (left_sibling->Is34Node()) {
1011 RightRotate(node, index - 1);
1012 break;
1013 }
1014 }
1015
1016 if (index < node->GetCount() - 1) {
1017 // right_child has right-sibling, we check if we can do
1018 // a rotate
1019 Node *right_sibling =
1020 node->GetItemRightChild(index + 1);
1021 if (right_sibling->Is34Node()) {
1022 LeftRotate(node, index + 1);
1023 break;
1024 }
1025 }
1026
1027 // we do a merge. We avoid merging the target item, which
1028 // may trigger another merge in the recursion process.
1029 if (index > 0) {
1030 Merge(node, index - 1);
1031 break;
1032 }
1033
1034 Merge(node, index + 1);
1035
1036 } while (false);
1037 }
1038
1039 // refresh the left_child and right_child since they may be invalid
1040 // because of merge
1041 left_child = node->GetItemLeftChild(index);
1042 right_child = node->GetItemRightChild(index);
1043
1044 if (left_child->Is34Node()) {
1045 int64_t predecessor_item = GetTreeMaxItem(left_child);
1046 node->SetItem(node->GetItemIndex(item), predecessor_item);
1047
1048 node = left_child;
1049 item = predecessor_item;
1050 continue;
1051 }
1052
1053 if (right_child->Is34Node()) {
1054 int64_t successor_item = GetTreeMinItem(right_child);
1055 node->SetItem(node->GetItemIndex(item), successor_item);
1056 node = right_child;
1057 item = successor_item;
1058 continue;
1059 }
1060 }
1061
1062 Node *next_node = node->GetNextPossibleChild(item);
1063
1064 if (next_node->Is34Node()) {
1065 node = next_node;
1066 continue;
1067 }
1068
1069 if (TryRightRotate(node, next_node)) {
1070 node = next_node;
1071 continue;
1072 }
1073
1074 if (TryLeftRotate(node, next_node)) {
1075 node = next_node;
1076 continue;
1077 }
1078
1079 // get here means both left sibling and right sibling of next_node is
1080 // 2-node, so we do merge
1081 int8_t child_index = node->GetChildIndex(next_node);
1082 if (child_index > 0) {
1083 node = Merge(node, child_index - 1);
1084 } else {
1085 node = Merge(node, child_index);
1086 }
1087
1088 } // while
1089
1090 return false;
1091}
1092
1099 assert(tree);
1100 int64_t max = 0;
1101
1102 while (tree) {
1103 max = tree->GetMaxItem();
1104 tree = tree->GetRightmostChild();
1105 }
1106
1107 return max;
1108}
1109
1116 assert(tree);
1117 int64_t min = 0;
1118
1119 while (tree) {
1120 min = tree->GetMinItem();
1121 tree = tree->GetLeftmostChild();
1122 }
1123
1124 return min;
1125}
1126
1131void Tree234::Print(const char *file_name) {
1132 if (!file_name) {
1133 file_name = "out.dot";
1134 }
1135
1136 std::ofstream ofs;
1137
1138 ofs.open(file_name);
1139 if (!ofs) {
1140 std::cout << "create tree dot file failed, " << file_name << std::endl;
1141 return;
1142 }
1143
1144 ofs << "digraph G {\n";
1145 ofs << "node [shape=record]\n";
1146
1147 int64_t index = 0;
1148
1151 struct NodeInfo {
1152 Node *node;
1153 int64_t index;
1155 };
1156
1157 std::queue<NodeInfo> q;
1158
1159 if (root_) {
1160 // print root node
1161 PrintNode(ofs, root_, -1, index, 0);
1162
1163 NodeInfo ni{};
1164 ni.node = root_;
1165 ni.index = index;
1166
1167 q.push(ni);
1168
1169 while (!q.empty()) {
1170 NodeInfo node_info = q.front();
1171 q.pop();
1172
1173 assert(node_info.node->GetCount() > 0);
1174
1175 if (!node_info.node->IsLeaf()) {
1176 if (node_info.node->GetCount() > 0) {
1177 PrintNode(ofs, node_info.node->GetChild(0), node_info.index,
1178 ++index, 0);
1179 ni.node = node_info.node->GetChild(0);
1180 ni.index = index;
1181 q.push(ni);
1182
1183 PrintNode(ofs, node_info.node->GetChild(1), node_info.index,
1184 ++index, 1);
1185 ni.node = node_info.node->GetChild(1);
1186 ni.index = index;
1187 q.push(ni);
1188 }
1189
1190 if (node_info.node->GetCount() > 1) {
1191 PrintNode(ofs, node_info.node->GetChild(2), node_info.index,
1192 ++index, 2);
1193 ni.node = node_info.node->GetChild(2);
1194 ni.index = index;
1195 q.push(ni);
1196 }
1197
1198 if (node_info.node->GetCount() > 2) {
1199 PrintNode(ofs, node_info.node->GetChild(3), node_info.index,
1200 ++index, 3);
1201 ni.node = node_info.node->GetChild(3);
1202 ni.index = index;
1203 q.push(ni);
1204 }
1205 }
1206 }
1207 }
1208
1209 ofs << "}\n";
1210 ofs.close();
1211}
1212
1226void Tree234::PrintNode(std::ofstream &ofs, Node *node, int64_t parent_index,
1227 int64_t index, int8_t parent_child_index) {
1228 assert(node);
1229
1230 switch (node->GetCount()) {
1231 case 1:
1232 ofs << "node_" << index << " [label=\"<f0> " << node->GetItem(0)
1233 << "\"]\n";
1234 break;
1235 case 2:
1236 ofs << "node_" << index << " [label=\"<f0> " << node->GetItem(0)
1237 << " | <f1> " << node->GetItem(1) << "\"]\n";
1238 break;
1239 case 3:
1240 ofs << "node_" << index << " [label=\"<f0> " << node->GetItem(0)
1241 << " | <f1> " << node->GetItem(1) << "| <f2> "
1242 << node->GetItem(2) << "\"]\n";
1243 break;
1244
1245 default:
1246 break;
1247 }
1248
1249 // draw the edge
1250 if (parent_index >= 0) {
1251 ofs << "node_" << parent_index << ":f"
1252 << (parent_child_index == 0 ? 0 : parent_child_index - 1) << ":"
1253 << (parent_child_index == 0 ? "sw" : "se") << " -> node_" << index
1254 << "\n";
1255 }
1256}
1257} // namespace tree_234
1258} // namespace data_structures
1259
1260
1263static void test1() {
1264 std::array<int16_t, 13> arr = {3, 1, 5, 4, 2, 9, 10, 8, 7, 6, 16, 13, 14};
1266
1267 for (auto i : arr) {
1268 tree.Insert(i);
1269 }
1270
1271 // tree.Remove(10);
1272 tree.Remove(5);
1273 tree.Print();
1274}
1275
1281static void test2(int64_t n) {
1283
1284 for (int64_t i = 0; i < n; i++) {
1285 tree.Insert(i);
1286 }
1287
1288 tree.Traverse();
1289 tree.Print((std::to_string(n) + ".dot").c_str());
1290}
1291
1298int main(int argc, char *argv[]) {
1299 if (argc < 2) {
1300 test1(); // execute 1st test
1301 } else {
1302 test2(std::stoi(argv[1])); // execute 2nd test
1303 }
1304
1305 return 0;
1306}
struct node { int data; int height; struct node *left; struct node *right;} node
for std::queue
Definition avltree.cpp:13
2-3-4 tree node class
Definition tree_234.cpp:35
Node * GetChild(int8_t index)
Get the child pointer at position of index.
Definition tree_234.cpp:252
bool Contains(int64_t item)
Check if item is in the node.
Definition tree_234.cpp:92
int64_t GetMaxItem()
Get max item (rightmost) in the current node.
Definition tree_234.cpp:120
Node * RemoveItemByIndex(int8_t index, bool keep_left)
Insert a value to the index position.
Definition tree_234.cpp:217
void InsertItemByIndex(int8_t index, int64_t item, Node *with_child, bool to_left=true)
Insert a value to the index position.
Definition tree_234.cpp:189
Node * GetItemRightChild(int8_t item_index)
Get right child of item at item_index.
Definition tree_234.cpp:291
int64_t GetItem(int8_t index)
Get item of the \index index.
Definition tree_234.cpp:133
bool IsFull()
Check if node is a full (4-node)
Definition tree_234.cpp:73
int64_t GetMinItem()
get min item (leftmost) in the current node
Definition tree_234.cpp:126
bool IsLeaf()
Check if node is a leaf.
Definition tree_234.cpp:67
int8_t GetItemIndex(int64_t item)
Get the index of the item in the node, 0-based.
Definition tree_234.cpp:107
bool Is34Node()
Check if node is a 3-node or 4-node, this is useful when we delete item from 2-3-4 tree.
Definition tree_234.cpp:85
Node * GetRightmostChild()
Get rightmose child of the current node.
Definition tree_234.cpp:265
std::array< int64_t, 3 > items
store items
Definition tree_234.cpp:315
int InsertItem(int item)
Insert item to the proper position of the node and return the position index.
Definition tree_234.cpp:163
Node * GetNextPossibleChild(int64_t item)
Get next node which is possibly contains item.
Definition tree_234.cpp:304
int8_t count
track the current item count
Definition tree_234.cpp:319
void SetItem(int8_t index, int64_t new_item)
Set item value at position of index.
Definition tree_234.cpp:140
int8_t GetCount()
Get the item count that current saved in the node.
Definition tree_234.cpp:50
void SetChild(int8_t index, Node *child)
Set child pointer to the position of index.
Definition tree_234.cpp:259
Node * GetItemLeftChild(int8_t item_index)
Get left child of item at item_index.
Definition tree_234.cpp:278
Node * GetLeftmostChild()
Get leftmose child of the current node.
Definition tree_234.cpp:271
Node(int64_t item)
Node constructor.
Definition tree_234.cpp:41
std::array< Node *, 4 > children
store the children pointers
Definition tree_234.cpp:317
int8_t GetChildIndex(Node *child)
Get the child's index of the children array.
Definition tree_234.cpp:237
void SetCount(int8_t c)
Set the item count of the node.
Definition tree_234.cpp:61
bool Is2Node()
Check if node is a 2-node.
Definition tree_234.cpp:79
void InsertPreSplit(int64_t item)
A insert implementation of pre-split.
Definition tree_234.cpp:585
Node * MergeNode(Node *dst_node, Node *node)
A helper function used during post-merge insert.
Definition tree_234.cpp:700
void DeleteNode(Node *tree)
Recursive release the tree.
Definition tree_234.cpp:547
void Print(const char *file_name=nullptr)
Print tree into a dot file.
Node * root_
root node of the tree
Definition tree_234.cpp:538
Node * Merge(Node *parent, int8_t index)
Merge the item at index of the parent node, and its left and right child.
Definition tree_234.cpp:895
Node * SplitNode(Node *node)
Split a 4-node to 1 parent and 2 children, and return the parent node.
Definition tree_234.cpp:745
bool Remove(int64_t item)
Remove item from tree.
Definition tree_234.cpp:929
bool RemovePreMerge(Node *node, int64_t item)
Main function implement the pre-merge remove operation.
Definition tree_234.cpp:937
int64_t GetTreeMinItem(Node *tree)
Get the min item of the tree.
void Insert(int64_t item)
Insert item to tree.
Definition tree_234.cpp:655
void Traverse()
In-order traverse.
Definition tree_234.cpp:562
void InsertPostMerge(int64_t item)
A insert implementation of post-merge.
Definition tree_234.cpp:637
bool TryLeftRotate(Node *parent, Node *to_child)
A handy function to try if we can do a left rotate to the target node.
Definition tree_234.cpp:778
int64_t GetTreeMaxItem(Node *tree)
Get the max item of the tree.
void MergeNodeNotFull(Node *dst_node, Node *node)
Merge node to a not-full target node.
Definition tree_234.cpp:730
void LeftRotate(Node *parent, int8_t index)
Do the actual left rotate operation.
Definition tree_234.cpp:869
void RightRotate(Node *parent, int8_t index)
Do the actual right rotate operation.
Definition tree_234.cpp:845
bool TryRightRotate(Node *parent, Node *to_child)
A handy function to try if we can do a right rotate to the target node.
Definition tree_234.cpp:813
void PrintNode(std::ofstream &ofs, Node *node, int64_t parent_index, int64_t index, int8_t parent_child_index)
Print the tree to a dot file. You can convert it to picture with graphviz.
static void test2()
Self-implementations, 2nd test.
int main()
Main function.
for IO operations
Functions for 2–3–4 tree
static void test1()
simple test to insert a given array and delete some item, and print the tree