- More optimization on fennec::sequence. There are areas that could be improved, but the running time is now within margin. It can be revisited later if this data-structure becomes the focus of a performance critical task.
This commit is contained in:
@@ -63,31 +63,28 @@ public:
|
||||
protected:
|
||||
struct node {
|
||||
value_t value;
|
||||
size_t parent, left, right;
|
||||
size_t depth;
|
||||
size_t parent;
|
||||
size_t child[2];
|
||||
|
||||
constexpr node()
|
||||
: value(nullopt)
|
||||
, parent(npos), left(npos), right(npos)
|
||||
, depth(0) {
|
||||
: value()
|
||||
, parent(npos), child{ npos, npos } {
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr node(size_t p, size_t l, size_t r, size_t d, ArgsT&&...args)
|
||||
constexpr node(size_t p, size_t l, size_t r, ArgsT&&...args)
|
||||
: value(fennec::forward<ArgsT>(args)...)
|
||||
, parent(p), left(l), right(r)
|
||||
, depth(d) {
|
||||
, parent(p), child{ l, r } {
|
||||
}
|
||||
|
||||
constexpr ~node() {
|
||||
parent = npos;
|
||||
left = npos;
|
||||
right = npos;
|
||||
depth = npos;
|
||||
parent = npos;
|
||||
child[0] = npos;
|
||||
child[1] = npos;
|
||||
}
|
||||
|
||||
size_t& operator[](bool d) {
|
||||
return d ? right : left;
|
||||
return child[d];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -204,7 +201,7 @@ public:
|
||||
/// \param i The node id
|
||||
/// \returns The left child of node `i`
|
||||
constexpr size_t left(size_t i) const {
|
||||
return i == npos ? npos : _table[i].left;
|
||||
return i == npos ? npos : _table[i].child[false];
|
||||
}
|
||||
|
||||
///
|
||||
@@ -212,7 +209,7 @@ public:
|
||||
/// \param i The node id
|
||||
/// \returns The right child of node `i`
|
||||
constexpr size_t right(size_t i) const {
|
||||
return i == npos ? npos : _table[i].right;
|
||||
return i == npos ? npos : _table[i].child[true];
|
||||
}
|
||||
|
||||
///
|
||||
@@ -221,7 +218,7 @@ public:
|
||||
/// \param dir The direction to go `true` for right, `false` for left
|
||||
/// \returns The child in the direction specified by `dir`
|
||||
constexpr size_t child(size_t i, bool dir) const {
|
||||
return dir ? right(i) : left(i);
|
||||
return i == npos ? npos : _table[i].child[dir];
|
||||
}
|
||||
|
||||
///
|
||||
@@ -237,10 +234,15 @@ public:
|
||||
/// \param i The id of the node
|
||||
/// \returns The id of the sibling of `i`
|
||||
constexpr size_t sibling(size_t i) const {
|
||||
size_t p = parent(i);
|
||||
size_t l = left(p);
|
||||
size_t r = right(p);
|
||||
return i == l ? r : l;
|
||||
if (i == npos) {
|
||||
return npos;
|
||||
}
|
||||
if (i == _root) {
|
||||
return npos;
|
||||
}
|
||||
size_t p = _parent(i);
|
||||
bool d = i == _right(p);
|
||||
return _child(p, d);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -248,7 +250,12 @@ public:
|
||||
/// \param i The node id
|
||||
/// \returns The depth of node `i`
|
||||
constexpr size_t depth(size_t i) const {
|
||||
return i >= _table.size() ? npos : _table[i].depth;
|
||||
size_t d = 0;
|
||||
while (i != npos) {
|
||||
i = _parent(i);
|
||||
++d;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
///
|
||||
@@ -259,8 +266,8 @@ public:
|
||||
if (i >= _table.size()) {
|
||||
return npos;
|
||||
}
|
||||
while (_table[i].left != npos) {
|
||||
i = _table[i].left;
|
||||
while (_table[i].child[false] != npos) {
|
||||
i = _table[i].child[false];
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -273,8 +280,8 @@ public:
|
||||
if (i >= _table.size()) {
|
||||
return npos;
|
||||
}
|
||||
while (_table[i].right != npos) {
|
||||
i = _table[i].right;
|
||||
while (_table[i].right[false] != npos) {
|
||||
i = _table[i].right[false];
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -375,71 +382,19 @@ public:
|
||||
return this->_insert_right(p, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Perform a Left Tree Rotation at `i`
|
||||
/// \param i The root node for the rotation
|
||||
constexpr void rotate_left(size_t i) {
|
||||
if (i >=_table.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t l = i;
|
||||
size_t p = parent(l);
|
||||
size_t r = right(l);
|
||||
|
||||
if (p == npos) {
|
||||
_root = r;
|
||||
} else if (l == _table[p].left) {
|
||||
_table[p].left = r;
|
||||
} else {
|
||||
_table[p].right = r;
|
||||
}
|
||||
|
||||
_table[l].parent = r;
|
||||
_table[l].right = _table[r].left;
|
||||
|
||||
_table[r].parent = p;
|
||||
_table[r].left = l;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Perform a Right Tree Rotation at `i`
|
||||
/// \param i The root node for the rotation
|
||||
constexpr void rotate_right(size_t i) {
|
||||
if (i >=_table.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t r = i;
|
||||
size_t p = parent(r);
|
||||
size_t l = left(r);
|
||||
|
||||
if (p == npos) {
|
||||
_root = l;
|
||||
} else if (r == _table[p].left) {
|
||||
_table[p].left = l;
|
||||
} else {
|
||||
_table[p].right = l;
|
||||
}
|
||||
|
||||
_table[r].parent = l;
|
||||
_table[r].left = _table[l].right;
|
||||
|
||||
_table[l].parent = p;
|
||||
_table[l].right = r;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Perform a Tree Rotation at `i` in the specified direction
|
||||
/// \param i The root node for the rotation
|
||||
/// \param dir The direction to rotate, `true` for right, `false` for left
|
||||
constexpr size_t rotate(size_t sub, bool dir) {
|
||||
if (sub >=_table.size()) {
|
||||
if (sub == npos) {
|
||||
return npos;
|
||||
}
|
||||
size_t sub_parent = parent(sub);
|
||||
size_t new_root = child(sub, not dir);
|
||||
size_t new_child = child(new_root, dir);
|
||||
size_t sub_parent = _parent(sub);
|
||||
size_t new_root = _child(sub, not dir);
|
||||
size_t new_child = _child(new_root, dir);
|
||||
|
||||
_child(sub, not dir) = new_child;
|
||||
if (new_child != npos) {
|
||||
@@ -457,6 +412,40 @@ public:
|
||||
return new_root;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Move Insertion, bool d, constructs a new node as the child of `p`
|
||||
/// \details If the child of `p` already exists, the move assignment operator is used instead
|
||||
/// \param p The parent node
|
||||
/// \param d The direction to insert
|
||||
/// \param val The object to move into the new node
|
||||
/// \returns The id of the new node
|
||||
constexpr size_t insert(size_t p, bool d, value_t&& val) {
|
||||
return this->_insert(p, d, fennec::forward<value_t>(val));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Copy Insertion, bool d, constructs a new node as the child of `p`
|
||||
/// \details If the child of `p` already exists, the copy assignment operator is used instead
|
||||
/// \param p The parent node
|
||||
/// \param d The direction to insert
|
||||
/// \param val The object to copy to the new node
|
||||
/// \returns The id of the new node
|
||||
constexpr size_t insert(size_t p, bool d, const value_t& val) {
|
||||
return this->_insert(p, d, val);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Emplace Insertion, constructs a new node as the child of `p`
|
||||
/// \details If the child of `p` already exists, the move assignment operator is used instead
|
||||
/// \param p The parent node
|
||||
/// \param d The direction to insert
|
||||
/// \param args The arguments to construct the new node with
|
||||
/// \returns The id of the new node
|
||||
template<typename...ArgsT>
|
||||
constexpr size_t emplace(size_t p, bool d, ArgsT&&...args) {
|
||||
return this->_insert(p, d, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Clears the tree, destroying all elements
|
||||
constexpr void clear() {
|
||||
@@ -470,11 +459,11 @@ public:
|
||||
size_t i = queue.front();
|
||||
queue.pop_front();
|
||||
|
||||
if (_table[i].left != npos) {
|
||||
queue.push_front(_table[i].left);
|
||||
if (_right(i) != npos) {
|
||||
queue.push_front(_right(i));
|
||||
}
|
||||
if (_table[i].right != npos) {
|
||||
queue.push_front(_table[i].right);
|
||||
if (_left(i) != npos) {
|
||||
queue.push_front(_left(i));
|
||||
}
|
||||
|
||||
fennec::destruct(&_table[i]);
|
||||
@@ -761,16 +750,14 @@ protected:
|
||||
if (i != npos) {
|
||||
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
|
||||
} else {
|
||||
size_t d = 1;
|
||||
i = _next_free();
|
||||
if (p != npos) {
|
||||
d = depth(p) + 1;
|
||||
_table[p].left = i;
|
||||
_left(p) = i;
|
||||
}
|
||||
if (_root == npos) {
|
||||
_root = i;
|
||||
}
|
||||
fennec::construct(&_table[i], p, npos, npos, d, fennec::forward<ArgsT>(args)...);
|
||||
fennec::construct(&_table[i], p, npos, npos, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -780,24 +767,38 @@ protected:
|
||||
size_t i = p == npos ? _root : _right(p);
|
||||
if (i != npos) {
|
||||
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
|
||||
if (p == npos || _root == npos) {
|
||||
_root = i;
|
||||
}
|
||||
} else {
|
||||
size_t d = 1;
|
||||
i = _next_free();
|
||||
if (p != npos) {
|
||||
d = depth(p) + 1;
|
||||
_table[p].right = i;
|
||||
_right(p) = i;
|
||||
}
|
||||
if (_root == npos) {
|
||||
_root = i;
|
||||
}
|
||||
fennec::construct(&_table[i], p, npos, npos, d, fennec::forward<ArgsT>(args)...);
|
||||
fennec::construct(&_table[i], p, npos, npos, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr size_t _insert(size_t p, bool d, ArgsT&&...args) {
|
||||
size_t i = p == npos ? _root : _child(p, d);
|
||||
if (i != npos) {
|
||||
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
|
||||
return i;
|
||||
}
|
||||
|
||||
i = _next_free();
|
||||
if (p != npos) {
|
||||
_child(p, d) = i;
|
||||
}
|
||||
if (_root == npos) {
|
||||
_root = i;
|
||||
}
|
||||
fennec::construct(&_table[i], p, npos, npos, fennec::forward<ArgsT>(args)...);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
constexpr size_t& _parent(size_t i) {
|
||||
return _table[i].parent;
|
||||
@@ -808,19 +809,19 @@ protected:
|
||||
}
|
||||
|
||||
constexpr size_t& _left(size_t i) {
|
||||
return _table[i].left;
|
||||
return _table[i].child[false];
|
||||
}
|
||||
|
||||
constexpr size_t& _right(size_t i) {
|
||||
return _table[i].right;
|
||||
return _table[i].child[true];
|
||||
}
|
||||
|
||||
constexpr size_t& _child(size_t i, bool dir) {
|
||||
return dir ? _right(i) : _left(i);
|
||||
return _table[i].child[dir];
|
||||
}
|
||||
|
||||
constexpr size_t& _sibling(size_t i) {
|
||||
size_t p = parent(i);
|
||||
size_t p = _parent(i);
|
||||
size_t& l = _left(p);
|
||||
size_t& r = _right(p);
|
||||
return i == l ? l : r;
|
||||
|
||||
@@ -109,12 +109,10 @@ protected:
|
||||
using base_t::left_most;
|
||||
using base_t::right_most;
|
||||
|
||||
using base_t::insert_left;
|
||||
using base_t::insert_right;
|
||||
using base_t::emplace_left;
|
||||
using base_t::emplace_right;
|
||||
|
||||
using base_t::rotate;
|
||||
using base_t::rotate_left;
|
||||
using base_t::rotate_right;
|
||||
|
||||
using base_t::_table;
|
||||
using base_t::_freed;
|
||||
@@ -159,9 +157,9 @@ public:
|
||||
size_t node = _root;
|
||||
while (node != npos) {
|
||||
if (_compare(val, _value(node))) {
|
||||
node = left(node);
|
||||
node = _left(node);
|
||||
} else if (_compare(_value(node), val)) {
|
||||
node = right(node);
|
||||
node = _right(node);
|
||||
} else {
|
||||
return sequence::iterator(this, _root, node);
|
||||
}
|
||||
@@ -325,8 +323,8 @@ protected:
|
||||
if (n == _root) { // Only recolor if not the root node
|
||||
_color(n) = c;
|
||||
}
|
||||
_color(left(n)) = !_color(left(n)) ;
|
||||
_color(right(n)) = !_color(right(n));
|
||||
_color(_left(n)) = !_color(_left(n)) ;
|
||||
_color(_right(n)) = !_color(_right(n));
|
||||
}
|
||||
|
||||
// run-of-the-mill bst insert
|
||||
@@ -335,7 +333,7 @@ protected:
|
||||
value_t val(fennec::forward<ArgsT>(args)...);
|
||||
|
||||
if (_root == npos) {
|
||||
return _root = insert_left(npos, node_t(fennec::move(val), red));
|
||||
return _root = base_t::emplace(npos, false, fennec::move(val), red);
|
||||
}
|
||||
|
||||
size_t i = _root;
|
||||
@@ -344,49 +342,50 @@ protected:
|
||||
p = i;
|
||||
|
||||
if (_compare(val, _value(i))) {
|
||||
i = left(i);
|
||||
i = _left(i);
|
||||
} else if (_compare(_value(i), val)) {
|
||||
i = right(i);
|
||||
i = _right(i);
|
||||
} else {
|
||||
return i;
|
||||
return npos;
|
||||
}
|
||||
}
|
||||
|
||||
if (_compare(val, _value(p))) {
|
||||
return insert_left(p, node_t(fennec::move(val), red));
|
||||
} else {
|
||||
return insert_right(p, node_t(fennec::move(val), red));
|
||||
}
|
||||
bool d = _compare(val, _value(p));
|
||||
return base_t::emplace(p, !d, fennec::move(val), red);
|
||||
}
|
||||
|
||||
// This makes some cheats given that the structure is modified only by internal functions
|
||||
// If such is the case, ONLY LL, LR, RL, and RR will show up
|
||||
// Then we just need to handle splitting a 4-node
|
||||
constexpr void _fix_insert(size_t n) {
|
||||
size_t p = parent(n);
|
||||
if (n == npos) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t p = _parent(n);
|
||||
while (n != _root && color(n) == red && color(p) == red) {
|
||||
size_t g = parent(p);
|
||||
bool d = n == right(p);
|
||||
bool r = p == right(g);
|
||||
size_t u = child(g, !r);
|
||||
size_t g = _parent(p);
|
||||
bool d = n == _right(p);
|
||||
bool r = p == _right(g);
|
||||
size_t u = _child(g, !r);
|
||||
|
||||
if (color(u) == red) {
|
||||
_recolor(g);
|
||||
n = g;
|
||||
p = parent(n);
|
||||
p = _parent(n);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (d != r) {
|
||||
rotate(p, r);
|
||||
n = p;
|
||||
p = parent(n);
|
||||
p = _parent(n);
|
||||
}
|
||||
|
||||
rotate(g, not r);
|
||||
fennec::swap(_color(p), _color(g));
|
||||
n = p;
|
||||
p = parent(n);
|
||||
p = _parent(n);
|
||||
}
|
||||
_color(_root) = black;
|
||||
}
|
||||
@@ -451,13 +450,13 @@ protected:
|
||||
}
|
||||
|
||||
size_t o = n;
|
||||
size_t p = parent(n);
|
||||
size_t p = _parent(n);
|
||||
if (p == npos) {
|
||||
_root = npos;
|
||||
return;
|
||||
}
|
||||
|
||||
bool d = n == right(p);
|
||||
bool d = n == _right(p);
|
||||
size_t c = _red_child(n);
|
||||
size_t s = npos;
|
||||
if (_color(n) == red || c != npos) {
|
||||
|
||||
Reference in New Issue
Block a user