isle/LEGO1/mxbinarytree.cpp
disinvite c80744dfde Some cleanup. Make red-black node color an enum as promised.
Not converting to template class just yet, because we lose the ability to meaningfully compare the code using the reccmp tool. My plan is to get the functions as close as possible to a match, then change over at the final step.
2023-08-01 23:21:02 -04:00

258 lines
5.6 KiB
C++

#include "mxbinarytree.h"
// 0x101013f0
TreeNode *MxBinaryTree::g_Node_Nil = NULL;
/*
// OFFSET: LEGO1 0x100ad170
TreeValue::~TreeValue()
{
// nothing.
}
*/
inline void MxBinaryTree::RightRotate(TreeNode *x)
{
TreeNode *y = x->m_child1;
x->m_child1 = y->m_child0;
if (y->m_child0 != g_Node_Nil)
y->m_child0->m_parent = x;
y->m_parent = x->m_parent;
if (m_root->m_parent != x) {
if (x != x->m_parent->m_child0) {
x->m_parent->m_child1 = y;
y->m_child0 = x;
x->m_parent = y;
} else {
x->m_parent->m_child0 = y;
y->m_child0 = x;
x->m_parent = y;
}
} else {
m_root->m_parent->m_child0 = y;
y->m_child0 = x;
x->m_parent = y;
}
}
inline void MxBinaryTree::LeftRotate(TreeNode *x)
{
TreeNode *y = x->m_child0;
x->m_child0 = y->m_child1;
if (y->m_child1 != g_Node_Nil)
y->m_child1->m_parent = x;
y->m_parent = x->m_parent;
if (m_root->m_parent != x) {
if (x != x->m_parent->m_child1) {
x->m_parent->m_child0 = y;
y->m_child1 = x;
x->m_parent = y;
} else {
x->m_parent->m_child1 = y;
y->m_child1 = x;
x->m_parent = y;
}
} else {
m_root->m_parent->m_child1 = y;
y->m_child1 = x;
x->m_parent = y;
}
}
inline TreeNode *MxBinaryTree::minimum(TreeNode *p_node)
{
// horrible. but it has to be this way to
// force a non-branching JMP to repeat the loop.
while (1) {
if (p_node->m_child1 == g_Node_Nil)
break;
p_node = p_node->m_child1;
}
return p_node;
}
// OFFSET: LEGO1 0x100ad480
void MxBinaryTree::Successor(TreeNode* &p_node)
{
// I think this is checking whether this is the tree "root" node
// i.e. MxBinaryTree->m_root
// The actual root is m_root->parent. There is an intentional loop here.
// If it is the "root" node, return the minimum value of the tree.
// We have a reference to it at m_root->m_child1.
if (p_node->m_color == RBNodeColor_Red
&& p_node->m_parent->m_parent == p_node) {
p_node = p_node->m_child1;
return;
}
if (p_node->m_child0 != g_Node_Nil) {
p_node = minimum(p_node->m_child0);
return;
}
// p_node->m_child0 *is* NIL, so go up a level and try it
TreeNode *y = p_node->m_parent;
while (p_node == y->m_child0) {
p_node = y;
y = y->m_parent;
}
}
// OFFSET: LEGO1 0x100ad4d0
void MxBinaryTree::Insert(TreeNode **p_output, TreeNode *p_leaf, TreeNode *p_parent, TreeValue *&p_value)
{
TreeNode *node = newTreeNode(p_parent, RBNodeColor_Red);
node->m_child0 = g_Node_Nil;
node->m_child1 = g_Node_Nil;
// TODO: ???
if (&node->m_value)
node->m_value = p_value;
this->m_nodeCount++;
// if tree is NOT empty
// if param_2 is tree_nil (always true I think?)
//
if (m_root != p_parent
&& p_leaf == g_Node_Nil
&& TreeValueCompare(p_value, p_parent->m_value)) {
p_parent->m_child1 = node;
if (m_root->m_child1 == p_parent)
// Set the tree minimum.
m_root->m_child1 = node;
} else {
p_parent->m_child0 = node;
if (m_root != p_parent) {
if (m_root->m_child0 == p_parent)
// Set the tree maximum.
m_root->m_child0 = node;
} else {
// Set the tree minimum and top node.
m_root->m_parent = node;
m_root->m_child1 = node;
}
}
// LAB_100ad593
// rebalance the tree
TreeNode *cur = node;
while (m_root->m_parent != cur) {
TreeNode *parent = cur->m_parent;
if (parent->m_color != RBNodeColor_Red)
break;
TreeNode *uncle = parent->m_parent->m_child0;
if (uncle == parent) {
// wrong uncle
uncle = parent->m_parent->m_child1;
if (uncle->m_color != RBNodeColor_Red) {
// 100ad5d3
if (parent->m_child1 == cur) {
cur = parent;
RightRotate(cur);
}
// LAB_100ad60f
cur->m_parent->m_color = RBNodeColor_Black;
cur->m_parent->m_parent->m_color = RBNodeColor_Red;
LeftRotate(cur->m_parent->m_parent);
continue;
}
} else {
// LAB_100ad67f
if (uncle->m_color != RBNodeColor_Red) {
if (parent->m_child0 == cur) {
cur = parent;
LeftRotate(cur);
}
// LAB_100ad60f
cur->m_parent->m_color = RBNodeColor_Black;
cur->m_parent->m_parent->m_color = RBNodeColor_Red;
RightRotate(cur->m_parent->m_parent);
continue;
}
}
// LAB_100ad72c
parent->m_color = RBNodeColor_Black;
uncle->m_color = RBNodeColor_Black;
parent->m_parent->m_color = RBNodeColor_Red;
cur = parent->m_parent;
}
m_root->m_parent->m_color = RBNodeColor_Black;
*p_output = node;
}
// OFFSET: LEGO1 0x100ad780
TreeNode *MxBinaryTree::Search(TreeValue*& p_value)
{
TreeNode *node_match = m_root;
TreeNode *t_node = node_match->m_parent;
while (t_node != g_Node_Nil) {
if (!TreeValueCompare(t_node->m_value, p_value)) {
// closest match?
// it either does match or is where we will insert the new node.
node_match = t_node;
t_node = t_node->m_child0;
} else {
t_node = t_node->m_child1;
}
}
return node_match;
}
// OFFSET: LEGO1 0x100ad7f0
void TreeValue::RefCountInc()
{
m_t0++;
}
// OFFSET: LEGO1 0x100ad800
void TreeValue::RefCountDec()
{
if (m_t0)
m_t0--;
}
// OFFSET: LEGO1 0x100af6d0 STUB
MxBinaryTree::~MxBinaryTree()
{
}
// OFFSET: LEGO1 0x100af7a0
void MxBinaryTree::Predecessor(TreeNode*& p_node)
{
// TODO
if (p_node->m_child1 != g_Node_Nil) {
p_node = minimum(p_node->m_child1);
return;
}
while (p_node->m_parent->m_child0 == p_node)
p_node = p_node->m_parent;
if (p_node->m_child1 == p_node->m_parent)
p_node = p_node->m_parent;
}