41 explicit Node(int64_t item)
43 items({{item, 0, 0}}),
44 children({{
nullptr,
nullptr,
nullptr,
nullptr}}) {}
93 for (int8_t i = 0; i <
count; i++) {
94 if (item ==
items[i]) {
108 for (int8_t i = 0; i <
count; i++) {
109 if (
items[i] == item) {
140 void SetItem(int8_t index, int64_t new_item) {
141 assert(index >= 0 && index <= 2);
143 items[index] = new_item;
171 for (i = 0; i <
count; i++) {
172 if (
items[i] > item) {
190 bool to_left =
true) {
193 for (int8_t i =
count - 1; i >= index; i--) {
199 int8_t start_index = to_left ? index : index + 1;
201 for (int8_t i =
count; i >= start_index; i--) {
218 assert(index >= 0 && index <
count);
220 for (int8_t i = index; i <
count - 1; i++) {
224 for (int8_t i = keep_left ? index + 1 : index; i <
count; i++) {
229 return removed_child;
238 for (int8_t i = 0; i <
count + 1; i++) {
279 if (item_index < 0 || item_index >
count - 1) {
292 if (item_index < 0 || item_index >
count - 1) {
306 for (i = 0; i <
count; i++) {
307 if (
items[i] > item) {
337 void Insert(int64_t item);
344 bool Remove(int64_t item);
354 void Print(
const char *file_name =
nullptr);
536 int64_t index, int8_t parent_child_index);
551 for (int8_t i = 0; i <= tree->
GetCount(); i++) {
564 std::cout << std::endl;
573 for (i = 0; i <
node->GetCount(); i++) {
575 std::cout <<
node->GetItem(i) <<
", ";
591 Node *parent =
nullptr;
596 std::unique_ptr<Node> tmp(
new Node(item));
601 if (
node->Contains(item)) {
605 if (
node->IsFull()) {
608 Node *cur_node =
nullptr;
610 if (item < node->GetItem(0)) {
611 cur_node =
node->GetChild(0);
613 cur_node =
node->GetChild(1);
629 node = parent->GetNextPossibleChild(item);
664 assert(tree !=
nullptr);
666 std::unique_ptr<Node> split_node;
675 split_node.reset(
Insert(next_node, item));
677 split_node.reset(
new Node(item));
681 return MergeNode(tree, split_node.get());
701 assert(dst_node !=
nullptr &&
node !=
nullptr);
703 if (!dst_node->
IsFull()) {
731 assert(dst_node &&
node && !dst_node->
IsFull() &&
node->Is2Node());
746 assert(
node->GetCount() == 3);
755 parent->SetChild(0, left);
756 parent->SetChild(1, right);
779 int to_child_index = parent->GetChildIndex(to_child);
782 if (to_child_index >= parent->GetCount()) {
786 Node *right_sibling = parent->GetChild(to_child_index + 1);
789 if (right_sibling->
Is2Node()) {
814 int8_t to_child_index = parent->GetChildIndex(to_child);
817 if (to_child_index <= 0) {
821 Node *left_sibling = parent->GetChild(to_child_index - 1);
846 Node *left = parent->GetItemLeftChild(index);
847 Node *right = parent->GetItemRightChild(index);
849 assert(left && left->Is34Node());
850 assert(right && right->
Is2Node());
853 left->GetRightmostChild(),
true);
854 parent->SetItem(index, left->GetMaxItem());
855 left->RemoveItemByIndex(left->GetCount() - 1,
true);
870 Node *left = parent->GetItemLeftChild(index);
871 Node *right = parent->GetItemRightChild(index);
874 assert(left && left->Is2Node());
876 left->InsertItemByIndex(left->GetCount(), parent->GetItem(index),
900 Node *left_child = parent->GetItemLeftChild(index);
901 Node *right_child = parent->GetItemRightChild(index);
905 int64_t item = parent->GetItem(index);
916 parent->RemoveItemByIndex(index,
true);
939 if (
node->IsLeaf()) {
940 if (
node->Contains(item)) {
941 if (
node->Is2Node()) {
946 node->RemoveItemByIndex(
node->GetItemIndex(item),
true);
954 if (
node->Contains(item)) {
955 int8_t index =
node->GetItemIndex(item);
959 Node *left_child =
node->GetItemLeftChild(index);
960 Node *right_child =
node->GetItemRightChild(index);
961 assert(left_child && right_child);
988 if (
node->Is2Node()) {
1009 Node *left_sibling =
node->GetItemLeftChild(index - 1);
1016 if (index < node->GetCount() - 1) {
1019 Node *right_sibling =
1020 node->GetItemRightChild(index + 1);
1041 left_child =
node->GetItemLeftChild(index);
1042 right_child =
node->GetItemRightChild(index);
1046 node->SetItem(
node->GetItemIndex(item), predecessor_item);
1049 item = predecessor_item;
1055 node->SetItem(
node->GetItemIndex(item), successor_item);
1057 item = successor_item;
1062 Node *next_node =
node->GetNextPossibleChild(item);
1081 int8_t child_index =
node->GetChildIndex(next_node);
1082 if (child_index > 0) {
1133 file_name =
"out.dot";
1138 ofs.open(file_name);
1140 std::cout <<
"create tree dot file failed, " << file_name << std::endl;
1144 ofs <<
"digraph G {\n";
1145 ofs <<
"node [shape=record]\n";
1157 std::queue<NodeInfo> q;
1169 while (!q.empty()) {
1170 NodeInfo node_info = q.front();
1173 assert(node_info.node->GetCount() > 0);
1175 if (!node_info.node->IsLeaf()) {
1176 if (node_info.node->GetCount() > 0) {
1177 PrintNode(ofs, node_info.node->GetChild(0), node_info.index,
1179 ni.node = node_info.node->GetChild(0);
1183 PrintNode(ofs, node_info.node->GetChild(1), node_info.index,
1185 ni.node = node_info.node->GetChild(1);
1190 if (node_info.node->GetCount() > 1) {
1191 PrintNode(ofs, node_info.node->GetChild(2), node_info.index,
1193 ni.node = node_info.node->GetChild(2);
1198 if (node_info.node->GetCount() > 2) {
1199 PrintNode(ofs, node_info.node->GetChild(3), node_info.index,
1201 ni.node = node_info.node->GetChild(3);
1227 int64_t index, int8_t parent_child_index) {
1230 switch (
node->GetCount()) {
1232 ofs <<
"node_" << index <<
" [label=\"<f0> " <<
node->GetItem(0)
1236 ofs <<
"node_" << index <<
" [label=\"<f0> " <<
node->GetItem(0)
1237 <<
" | <f1> " <<
node->GetItem(1) <<
"\"]\n";
1240 ofs <<
"node_" << index <<
" [label=\"<f0> " <<
node->GetItem(0)
1241 <<
" | <f1> " <<
node->GetItem(1) <<
"| <f2> "
1242 <<
node->GetItem(2) <<
"\"]\n";
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
1264 std::array<int16_t, 13> arr = {3, 1, 5, 4, 2, 9, 10, 8, 7, 6, 16, 13, 14};
1267 for (
auto i : arr) {
1284 for (int64_t i = 0; i < n; i++) {
1289 tree.
Print((std::to_string(n) +
".dot").c_str());
1302 test2(std::stoi(argv[1]));
struct node { int data; int height; struct node *left; struct node *right;} node
for std::queue
Node * GetChild(int8_t index)
Get the child pointer at position of index.
bool Contains(int64_t item)
Check if item is in the node.
int64_t GetMaxItem()
Get max item (rightmost) in the current node.
Node * RemoveItemByIndex(int8_t index, bool keep_left)
Insert a value to the index position.
void InsertItemByIndex(int8_t index, int64_t item, Node *with_child, bool to_left=true)
Insert a value to the index position.
Node * GetItemRightChild(int8_t item_index)
Get right child of item at item_index.
int64_t GetItem(int8_t index)
Get item of the \index index.
bool IsFull()
Check if node is a full (4-node)
int64_t GetMinItem()
get min item (leftmost) in the current node
bool IsLeaf()
Check if node is a leaf.
int8_t GetItemIndex(int64_t item)
Get the index of the item in the node, 0-based.
bool Is34Node()
Check if node is a 3-node or 4-node, this is useful when we delete item from 2-3-4 tree.
Node * GetRightmostChild()
Get rightmose child of the current node.
std::array< int64_t, 3 > items
store items
int InsertItem(int item)
Insert item to the proper position of the node and return the position index.
Node * GetNextPossibleChild(int64_t item)
Get next node which is possibly contains item.
int8_t count
track the current item count
void SetItem(int8_t index, int64_t new_item)
Set item value at position of index.
int8_t GetCount()
Get the item count that current saved in the node.
void SetChild(int8_t index, Node *child)
Set child pointer to the position of index.
Node * GetItemLeftChild(int8_t item_index)
Get left child of item at item_index.
Node * GetLeftmostChild()
Get leftmose child of the current node.
Node(int64_t item)
Node constructor.
std::array< Node *, 4 > children
store the children pointers
int8_t GetChildIndex(Node *child)
Get the child's index of the children array.
void SetCount(int8_t c)
Set the item count of the node.
bool Is2Node()
Check if node is a 2-node.
void InsertPreSplit(int64_t item)
A insert implementation of pre-split.
Node * MergeNode(Node *dst_node, Node *node)
A helper function used during post-merge insert.
void DeleteNode(Node *tree)
Recursive release the tree.
void Print(const char *file_name=nullptr)
Print tree into a dot file.
Node * root_
root node of the tree
Node * Merge(Node *parent, int8_t index)
Merge the item at index of the parent node, and its left and right child.
Node * SplitNode(Node *node)
Split a 4-node to 1 parent and 2 children, and return the parent node.
bool Remove(int64_t item)
Remove item from tree.
bool RemovePreMerge(Node *node, int64_t item)
Main function implement the pre-merge remove operation.
int64_t GetTreeMinItem(Node *tree)
Get the min item of the tree.
void Insert(int64_t item)
Insert item to tree.
void Traverse()
In-order traverse.
void InsertPostMerge(int64_t item)
A insert implementation of post-merge.
bool TryLeftRotate(Node *parent, Node *to_child)
A handy function to try if we can do a left rotate to the target node.
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.
void LeftRotate(Node *parent, int8_t index)
Do the actual left rotate operation.
void RightRotate(Node *parent, int8_t index)
Do the actual right rotate operation.
bool TryRightRotate(Node *parent, Node *to_child)
A handy function to try if we can do a right rotate to the target node.
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.
static void test1()
simple test to insert a given array and delete some item, and print the tree