소스 검색

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


불러오는 중...
취소
저장