Bladeren bron

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 jaren geleden
bovenliggende
commit
23c077bc86
2 gewijzigde bestanden met toevoegingen van 136 en 44 verwijderingen
  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 Bestand weergeven

@@ -30,20 +30,26 @@ public:
{
if (!m_root)
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
{
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;
@@ -62,72 +68,155 @@ protected:
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 (this->m_child[0])
ret = this->m_child[0]->insert(key, value);
this->m_child[0]->insert_or_update(key, value);
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)
{
if (this->m_child[1])
ret = this->m_child[1]->insert(key, value);
this->m_child[1]->insert_or_update(key, value);
else
ret = this->m_child[1] = new tree_node(key, value);
this->m_child[1] = new tree_node(key, value);
}
else
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)
{
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 };
@@ -175,6 +264,11 @@ protected:
return this->m_stairs[1] - this->m_stairs[0];
}

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

protected:

K m_key;


+ 0
- 2
src/t/algorithm/avl_tree.cpp Bestand weergeven

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

#include <lol/engine-internal.h>

#include <lol/algorithm/avl_tree.h>

#include <lolunit.h>

namespace lol


Laden…
Annuleren
Opslaan