ソースを参照

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年前
コミット
23c077bc86
2個のファイルの変更136行の追加44行の削除
  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 ファイルの表示

@@ -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 ファイルの表示

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

#include <lol/engine-internal.h>

#include <lol/algorithm/avl_tree.h>

#include <lolunit.h>

namespace lol


読み込み中…
キャンセル
保存