Kaynağa Gözat

avl_tree: using contiguous buffer for node storage. Copy is still unsafe and this solution needs review before complete validation (sam… ?)

undefined
Guillaume Bittoun Sam Hocevar <sam@hocevar.net> 10 yıl önce
ebeveyn
işleme
85a88d457c
1 değiştirilmiş dosya ile 129 ekleme ve 30 silme
  1. +129
    -30
      src/lol/algorithm/avl_tree.h

+ 129
- 30
src/lol/algorithm/avl_tree.h Dosyayı Görüntüle

@@ -12,7 +12,6 @@

#pragma once


namespace lol
{

@@ -27,13 +26,21 @@ public:

bool insert(K const & key, V const & value)
{
bool created = false;
if (!m_root)
{
this->m_root = new tree_node(key, value, &this->m_root);
return true;

this->m_root = this->m_allocator.allocate(key, value, &this->m_root);
created = true;
}

return this->m_root->insert(key, value);
if (!created)
created = this->m_root->insert(key, value);

if (this->m_allocator.check_reallocation())
this->m_allocator.repair_root(&this->m_root);

return created;
}

bool erase(K const & key)
@@ -60,20 +67,18 @@ public:
return false;
}

virtual ~avl_tree()
{
if (this->m_root)
{
this->m_root->cascade_delete();
delete this->m_root;
}
}

protected:

class tree_node
{
public:
tree_node() :
m_parent_slot(nullptr)
{
m_child[0] = m_child[1] = nullptr;
m_stairs[0] = m_stairs[1] = 0;
}

tree_node(K key, V value, tree_node ** parent_slot) :
m_key(key),
m_value(value),
@@ -101,7 +106,7 @@ protected:
created = this->m_child[i]->insert(key, value);
else
{
this->m_child[i] = new tree_node(key, value, &this->m_child[i]);
this->m_child[i] = this->m_allocator->allocate(key, value, &this->m_child[i]);
created = true;
}

@@ -119,7 +124,7 @@ protected:
if (i < 0)
{
this->erase_self();
delete this;
this->m_allocator->deallocate(this);
return true;
}
else if(this->m_child[i]->erase(key))
@@ -196,21 +201,6 @@ protected:
return false;
}

void cascade_delete()
{
if (this->m_child[0])
{
this->m_child[0]->cascade_delete();
delete this->m_child[0];
}

if (this->m_child[1])
{
this->m_child[1]->cascade_delete();
delete this->m_child[1];
}
}

int get_balance()
{
return this->m_stairs[1] - this->m_stairs[0];
@@ -221,6 +211,113 @@ protected:
return this->m_key;
}

class tree_node_allocator
{
public:

tree_node_allocator() :
m_current(0),
m_size(1),
m_allocated(0)
{
m_buffers[0] = new tree_node[1];
m_buffers[1] = nullptr;
}

~tree_node_allocator()
{
delete[] this->m_buffers[this->m_current];
}

tree_node * allocate(K const & key, V const & value, tree_node ** parent_slot)
{
tree_node * new_node = &this->m_buffers[this->m_current][this->m_allocated++];

new_node->m_key = key;
new_node->m_value = value;
new_node->m_parent_slot = parent_slot;
new_node->m_allocator = this;

return new_node;
}

bool check_reallocation()
{
if (this->m_allocated == this->m_size)
{
int next = this->m_current ? 0 : 1;
size_t new_size = this->m_size * 2;

this->m_buffers[next] = new tree_node[new_size];

for (int i = 0 ; i < this->m_size ; ++i)
this->m_buffers[next][i] = this->m_buffers[this->m_current][i];

// Fix new links between child and parents and the new_array
for (int i = 0 ; i < this->m_size ; ++i)
{
for (int j = 0 ; j < 2 ; ++j)
{
if (this->m_buffers[this->m_current][i].m_child[j])
{
ptrdiff_t position0 = this->m_buffers[this->m_current][i].m_child[j] - this->m_buffers[this->m_current];
this->m_buffers[next][i].m_child[j] = &this->m_buffers[next][position0];
this->m_buffers[next][position0].m_parent_slot = &this->m_buffers[next][i].m_child[j];
}
}
}

delete[] this->m_buffers[this->m_current];
this->m_buffers[this->m_current] = nullptr;
this->m_current = next;
this->m_size = new_size;

return true;
}

return false;
}

void deallocate(tree_node * replace)
{
*replace = this->m_buffers[m_current][this->m_allocated - 1];
if (replace->m_parent_slot)
*replace->m_parent_slot = replace;

this->m_buffers[m_current][this->m_allocated - 1] = tree_node();

for (int i = 0 ; i < 2 ; ++i)
if (replace->m_child[i])
replace->m_child[i]->m_parent_slot = &replace->m_child[i];

--this->m_allocated;
}

void repair_root(tree_node ** root)
{
bool root_found = false;

for (int i = 0 ; i < this->m_allocated ; ++i)
{
if (this->m_buffers[this->m_current][i].m_parent_slot == root)
{
*root = &this->m_buffers[this->m_current][i];
root_found = true;
}
}

ASSERT(root_found); // Something went really bad
}

private:

tree_node * m_buffers[2];
int m_current;

size_t m_size;
ptrdiff_t m_allocated;
};

protected:

void erase_self()
@@ -261,9 +358,11 @@ protected:
int m_stairs[2];

tree_node ** m_parent_slot;
tree_node_allocator * m_allocator;
};

tree_node * m_root;
typename tree_node::tree_node_allocator m_allocator;
};

}

Yükleniyor…
İptal
Kaydet