Browse Source

avl_tree: refactoring insertion by using a bunch of more atomic method than the previous ones.

This new version of the insertion looks more maintainable even if probably less fast. To be reverted if too slow.
undefined
Guillaume Bittoun Sam Hocevar <sam@hocevar.net> 10 years ago
parent
commit
23c077bc86
2 changed files with 136 additions and 44 deletions
  1. +136
    -42
      src/lol/algorithm/avl_tree.h
  2. +0
    -2
      src/t/algorithm/avl_tree.cpp

+ 136
- 42
src/lol/algorithm/avl_tree.h View File

@@ -30,20 +30,26 @@ public:
{ {
if (!m_root) if (!m_root)
this->m_root = new tree_node(key, value); this->m_root = new tree_node(key, value);
else if (this->m_root->exists(key))
{
this->m_root->insert_or_update(key, value);
return false;
}
else else
{ {
tree_node * created = this->m_root->insert(key, value);
this->m_root->insert_or_update(key, value);
this->m_root->update_balance(key);
tree_node * node = this->m_root->get_unbalanced_parent(key);


if (created)
if (node)
{ {
this->m_root->path_update_balance(key);

tree_node * new_root = this->m_root->path_rebalance(key);
if (new_root)
this->m_root = new_root;
node->rebalance_children(key);
this->m_root->update_balance(node);
} }
else
return false;
else if (this->m_root->get_balance() == -2)
this->m_root = this->m_root->rotate(tree_node::CW);
else if (this->m_root->get_balance() == 2)
this->m_root = this->m_root->rotate(tree_node::CCW);
} }


return true; return true;
@@ -62,72 +68,155 @@ protected:
m_stairs[0] = m_stairs[1] = 0; m_stairs[0] = m_stairs[1] = 0;
} }


tree_node * insert(K const & key, V const & value)
bool exists(K key)
{ {
tree_node * ret = 0;
if (key < this->m_key)
{
if (this->m_child[0])
return this->m_child[0]->exists(key);
else
return false;
}
if (this->m_key < key)
{
if (this->m_child[1])
return this->m_child[1]->exists(key);
else
return false;
}

return true;
}


void insert_or_update(K const & key, V const & value)
{
if (key < this->m_key) if (key < this->m_key)
{ {
if (this->m_child[0]) if (this->m_child[0])
ret = this->m_child[0]->insert(key, value);
this->m_child[0]->insert_or_update(key, value);
else else
ret = this->m_child[0] = new tree_node(key, value);
this->m_child[0] = new tree_node(key, value);
} }
else if (this->m_key < key) else if (this->m_key < key)
{ {
if (this->m_child[1]) if (this->m_child[1])
ret = this->m_child[1]->insert(key, value);
this->m_child[1]->insert_or_update(key, value);
else else
ret = this->m_child[1] = new tree_node(key, value);
this->m_child[1] = new tree_node(key, value);
} }
else else
this->m_value = value; this->m_value = value;
}


return ret;
void update_balance(tree_node * node)
{
this->update_balance(node->m_key);
} }


int path_update_balance(K const & key)
void update_balance(K const & key)
{ {
if (key < this->m_key)
this->m_stairs[0] = lol::max(this->m_child[0]->path_update_balance(key), this->m_stairs[0]);
else if (this->m_key < key)
this->m_stairs[1] = lol::max(this->m_child[1]->path_update_balance(key), this->m_stairs[1]);
if (key < this->m_key && this->m_child[0])
this->m_child[0]->update_balance(key);
if (this->m_key < key && this->m_child[1])
this->m_child[1]->update_balance(key);


return lol::max(this->m_stairs[0], this->m_stairs[1]) + 1;
this->compute_balance();
} }


tree_node * path_rebalance(K const & key)
/* Increases stairs according that key is inserted.
* Do not call "increase_path" if key is not already present in the tree. */
void increase_path(K key)
{ {
if (key < this->m_key) if (key < this->m_key)
{ {
tree_node * node = this->m_child[0]->path_rebalance(key);
if (node)
{
this->m_child[0] = node;
--this->m_stairs[0];
}
this->m_child[0]->increase_path(key);
this->compute_balance();
} }
else if (this->m_key < key)
if (this->m_key < key)
{ {
tree_node * node = this->m_child[1]->path_rebalance(key);
if (node)
{
this->m_child[1] = node;
--this->m_stairs[1];
}
this->m_child[1]->increase_path(key);
this->compute_balance();
} }
}

/* Retrieve the parent of the deeper unbalanced node after key insertion.
* Do not call "get_unbalanced_parent" if key is not already present in the tree. */
tree_node * get_unbalanced_parent(K const & key)
{
tree_node * parent = nullptr;


if (this->get_balance() == 2)
if (key < this->m_key)
{ {
return this->rotate(CCW);
parent = this->m_child[0]->get_unbalanced_parent(key);

if (parent)
return parent;
else if (abs(this->m_child[0]->get_balance()) == 2)
return this;
} }
else if (this->get_balance() == -2)
if (this->m_key < key)
{ {
return this->rotate(CW);
parent = this->m_child[1]->get_unbalanced_parent(key);

if (parent)
return parent;
else if (abs(this->m_child[1]->get_balance()) == 2)
return this;
} }


ASSERT(lol::abs(this->m_stairs[1] - this->m_stairs[0]) < 3);
return 0;
return nullptr;
}

void rebalance_children(K const & key)
{
if (key < this->m_key)
{
if (this->m_child[0]->get_balance() == 2)
this->rotateLL();
if (this->m_child[0]->get_balance() == -2)
this->rotateLR();
}
else if (this->m_key < key)
{
if (this->m_child[1]->get_balance() == 2)
this->rotateRL();
if (this->m_child[1]->get_balance() == -2)
this->rotateRR();
}
else
ASSERT(false) // Do not rebalance the "this" node here
}

void rotateLL()
{
tree_node * newhead = this->m_child[0]->rotate(CCW);

this->m_child[0] = newhead;
this->compute_balance();
}

void rotateLR()
{
tree_node * newhead = this->m_child[0]->rotate(CW);

this->m_child[0] = newhead;
this->compute_balance();
}

void rotateRL()
{
tree_node * newhead = this->m_child[1]->rotate(CCW);

this->m_child[1] = newhead;
this->compute_balance();
}

void rotateRR()
{
tree_node * newhead = this->m_child[1]->rotate(CW);

this->m_child[1] = newhead;
this->compute_balance();
} }


enum Rotation { CW = 0, CCW = 1 }; enum Rotation { CW = 0, CCW = 1 };
@@ -175,6 +264,11 @@ protected:
return this->m_stairs[1] - this->m_stairs[0]; return this->m_stairs[1] - this->m_stairs[0];
} }


K get_key()
{
return this->m_key;
}

protected: protected:


K m_key; K m_key;


+ 0
- 2
src/t/algorithm/avl_tree.cpp View File

@@ -12,8 +12,6 @@


#include <lol/engine-internal.h> #include <lol/engine-internal.h>


#include <lol/algorithm/avl_tree.h>

#include <lolunit.h> #include <lolunit.h>


namespace lol namespace lol


Loading…
Cancel
Save