avl
This commit is contained in:
commit
33b21e79af
|
@ -0,0 +1,579 @@
|
|||
#include <fstream>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
// #define BALANCE_IN_POINTERS
|
||||
// #define NODE_REUSE
|
||||
|
||||
#define _max(a,b) (((a) > (b)) ? (a) : (b)) //mhhhm speedy
|
||||
// #define _max(a,b) ((a) > (b)) * (a) + ((b) > (a)) * (b)
|
||||
typedef unsigned long uintptr_t
|
||||
#define get_parent(node) ((Node *)((uintptr_t)(node)->parent & ~0x3))
|
||||
|
||||
#ifdef BALANCE_IN_POINTERS
|
||||
#define get_bf(node) (((int)((uintptr_t)(node)->parent & 0x3)) - 1 )
|
||||
#define get_balance(node) ((node)?(get_bf(node)):(0))
|
||||
#else
|
||||
#define get_bf(node) ((node)->balance)
|
||||
#define get_balance(node) ((node) ? get_bf(node) : (0))
|
||||
#endif
|
||||
|
||||
inline int _abs(int n) {
|
||||
int mask = n >> ((sizeof(int)*8) -1);
|
||||
return (mask + n)^mask;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class PointerStack {
|
||||
public:
|
||||
T* array;
|
||||
size_t capacity;
|
||||
size_t top;
|
||||
|
||||
PointerStack(size_t size) {
|
||||
capacity = size;
|
||||
array = size ? new T[capacity] : nullptr;
|
||||
top = -1;
|
||||
}
|
||||
|
||||
~PointerStack() {
|
||||
delete[] array;
|
||||
}
|
||||
|
||||
inline void push(T value) {
|
||||
if (isFull()) {
|
||||
size_t newCapacity = 2 * capacity;
|
||||
T *newArray = new T[newCapacity];
|
||||
|
||||
for (size_t i = 0; i <= top; ++i) {
|
||||
newArray[i] = array[i];
|
||||
}
|
||||
|
||||
capacity = newCapacity;
|
||||
delete[] array;
|
||||
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array[++top] = value;
|
||||
}
|
||||
|
||||
inline T pop() {
|
||||
if (empty()) {
|
||||
throw std::out_of_range("pop from empty stack");
|
||||
}
|
||||
|
||||
return array[top--];
|
||||
}
|
||||
|
||||
inline const T& peek() const {
|
||||
if (empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return array[top];
|
||||
}
|
||||
|
||||
inline bool empty() const {
|
||||
return top == size_t(-1);
|
||||
}
|
||||
|
||||
inline bool isFull() const {
|
||||
return top == capacity - 1;
|
||||
}
|
||||
|
||||
inline void flush () {
|
||||
if (empty())
|
||||
return;
|
||||
for (size_t i = 0; i <= top; ++i) {
|
||||
delete array[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Tree {
|
||||
public:
|
||||
Tree(
|
||||
#ifdef NODE_REUSE
|
||||
size_t stacksize = 0
|
||||
#endif
|
||||
) : root(nullptr), treeSize(0)
|
||||
#ifdef NODE_REUSE
|
||||
, stack(stacksize)
|
||||
#endif
|
||||
{}
|
||||
~Tree() {
|
||||
delete root;
|
||||
#ifdef NODE_REUSE
|
||||
if (stack.capacity)
|
||||
stack.flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
struct Node {
|
||||
Node(const T& data, Node* parent = nullptr) : data(data), left(nullptr), right(nullptr), parent(nullptr)
|
||||
#ifndef BALANCE_IN_POINTERS
|
||||
, balance(0)
|
||||
#endif
|
||||
{}
|
||||
|
||||
~Node() {
|
||||
delete left;
|
||||
delete right;
|
||||
}
|
||||
|
||||
T data;
|
||||
Node* left;
|
||||
Node* right;
|
||||
Node* parent;
|
||||
#ifndef BALANCE_IN_POINTERS
|
||||
int balance;
|
||||
#endif
|
||||
#ifndef __PROGTEST__
|
||||
void debugDotShow(std::ofstream &ofs) {
|
||||
if (left) {
|
||||
ofs << data << " -> " << left->data << '\n';
|
||||
left->debugDotShow(ofs);
|
||||
}
|
||||
if (right) {
|
||||
ofs << data << " -> " << right->data << '\n';
|
||||
right->debugDotShow(ofs);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
Node* root;
|
||||
size_t treeSize;
|
||||
#ifdef NODE_REUSE
|
||||
PointerStack<Node *> stack;
|
||||
#endif
|
||||
|
||||
size_t size() const { return treeSize; }
|
||||
const T* find(const T& value) const {
|
||||
Node* i = root;
|
||||
while (i) {
|
||||
if (i->data == value)
|
||||
break;
|
||||
i = i->data < value ? i->right : i->left;
|
||||
}
|
||||
return i ? &i->data : nullptr;
|
||||
}
|
||||
|
||||
bool erase(const T& value) {
|
||||
Node* i = root;
|
||||
while (i) {
|
||||
if (i->data == value)
|
||||
break;
|
||||
i = i->data < value ? i->right : i->left;
|
||||
}
|
||||
|
||||
if (!i)
|
||||
return false;
|
||||
|
||||
remove(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef __PROGTEST__
|
||||
void debugDotShow() {
|
||||
if (!root)
|
||||
return;
|
||||
std::ofstream ofs;
|
||||
ofs.open("viz.dot");
|
||||
ofs << "digraph Tree {\n";
|
||||
root->debugDotShow(ofs);
|
||||
ofs << "}";
|
||||
|
||||
ofs.close();
|
||||
system("cat viz.dot | dot -Tx11 &");
|
||||
|
||||
}
|
||||
|
||||
void testParent(Node *n) const {
|
||||
if (!n)
|
||||
return;
|
||||
if (n->left) {
|
||||
if (n->left->parent != n)
|
||||
throw std::logic_error(std::to_string(n->left->data) + " parent error");
|
||||
if (n->left == n)
|
||||
throw std::logic_error(std::to_string(n->data) + " selfchild");
|
||||
testParent(n->left);
|
||||
}
|
||||
if (n->right) {
|
||||
if (n->right->parent != n)
|
||||
throw std::logic_error(std::to_string(n->right->data) + " parent error");
|
||||
if (n->right == n)
|
||||
throw std::logic_error(std::to_string(n->data) + " selfchild");
|
||||
testParent(n->right);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void set_bf(Node* n, int bf) {
|
||||
#ifdef BALANCE_IN_POINTERS
|
||||
n->parent = (Node *)((uintptr_t)get_parent(n) | (uintptr_t)(bf+1));
|
||||
#else
|
||||
n->balance = bf;
|
||||
#endif
|
||||
}
|
||||
static inline void set_parent(Node* n, Node* parent) {
|
||||
#ifdef BALANCE_IN_POINTERS
|
||||
n->parent = (Node*)((uintptr_t)parent | ((uintptr_t)n->parent & 0x3));
|
||||
#else
|
||||
n->parent = parent;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool insert(T value) {
|
||||
Node* inserted;
|
||||
Node* parent = nullptr;
|
||||
Node* current = root;
|
||||
int bf, bfOld;
|
||||
|
||||
while (current) {
|
||||
parent = current;
|
||||
|
||||
if (value == current->data)
|
||||
return false;
|
||||
|
||||
current = value < current->data ? current->left : current->right;
|
||||
}
|
||||
|
||||
inserted = getEmptyNode(value);
|
||||
set_parent(inserted, parent);
|
||||
set_bf(inserted, 0);
|
||||
++treeSize;
|
||||
|
||||
if (parent) {
|
||||
if (inserted->data < parent->data)
|
||||
parent->left = inserted;
|
||||
else
|
||||
parent->right = inserted;
|
||||
} else {
|
||||
root = inserted;
|
||||
}
|
||||
|
||||
bf = 0;
|
||||
while(inserted) {
|
||||
parent = get_parent(inserted);
|
||||
|
||||
if (parent) {
|
||||
bfOld = get_bf(inserted);
|
||||
|
||||
if (parent->right == inserted) {
|
||||
inserted = balanceTree(inserted, bf);
|
||||
parent->right = inserted;
|
||||
}else {
|
||||
inserted = balanceTree(inserted, bf);
|
||||
parent->left = inserted;
|
||||
}
|
||||
|
||||
// parent bf
|
||||
if (!inserted->left && !inserted->right) {
|
||||
// leaf node
|
||||
if (parent->left == inserted) bf = -1;
|
||||
else bf = 1;
|
||||
} else {
|
||||
// index node
|
||||
bf = 0;
|
||||
if (_abs(bfOld) < _abs(get_bf(inserted))) {
|
||||
if (parent->left == inserted) bf = -1;
|
||||
else bf = 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if(inserted == root){
|
||||
root = balanceTree(root, bf);
|
||||
break;
|
||||
}
|
||||
if (bf == 0) break;
|
||||
|
||||
inserted = parent;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline Node* balanceTree(Node* n, int bf) {
|
||||
int bfChild;
|
||||
int heightDiff = get_balance(n) + bf;
|
||||
|
||||
if (n) {
|
||||
if(heightDiff < -1 && n->left) {
|
||||
// balance left
|
||||
if(get_balance(n->left) <= 0) {
|
||||
bfChild = get_bf(n->left);
|
||||
n = LL(n, heightDiff, &bfChild, nullptr);
|
||||
set_bf(n, bfChild);
|
||||
} else {
|
||||
n = LR(n, heightDiff);
|
||||
}
|
||||
} else if(heightDiff > 1 && n->right) {
|
||||
// balance right
|
||||
if(get_balance(n->right) >= 0) {
|
||||
bfChild = get_bf(n->right);
|
||||
n = RR(n, heightDiff, &bfChild, nullptr);
|
||||
set_bf(n, bfChild);
|
||||
} else {
|
||||
n = RL(n, heightDiff);
|
||||
}
|
||||
} else {
|
||||
set_bf(n, get_bf(n) + bf);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline Node* LL(Node* parent, int bfParent, int* bfChild, int* heightDiff) {
|
||||
int parentRight, leftChild, rightChild;
|
||||
Node *child = parent->left;
|
||||
|
||||
leftChild = (child->left)?(1):(0);
|
||||
rightChild = (child->right)?(1):(0);
|
||||
if (*bfChild < 0) {
|
||||
// child->left > child->right
|
||||
leftChild = rightChild - (*bfChild);
|
||||
parentRight = leftChild + 1 + bfParent;
|
||||
if (heightDiff)
|
||||
*heightDiff = _max(leftChild, _max(rightChild, parentRight)+1) - (leftChild + 1);
|
||||
|
||||
} else {
|
||||
// child->left <= child->right
|
||||
rightChild = leftChild + (*bfChild);
|
||||
parentRight = rightChild + 1 + bfParent;
|
||||
if (heightDiff)
|
||||
*heightDiff = _max(leftChild, _max(rightChild, parentRight)+1) - (rightChild + 1);
|
||||
}
|
||||
*bfChild = (_max(rightChild, parentRight) + 1) - leftChild;
|
||||
set_bf(parent, parentRight - rightChild);
|
||||
|
||||
parent->left = child->right;
|
||||
if (child->right)
|
||||
set_parent(child->right, parent);
|
||||
child->right = parent;
|
||||
set_parent(child, get_parent(parent));
|
||||
set_parent(parent, child);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
static inline Node* RR(Node* parent, int bfParent, int* bfChild, int* heightDiff) {
|
||||
int parentLeft, childLeft, childRight;
|
||||
Node *child = parent->right;
|
||||
|
||||
childLeft = (child->left)?(1):(0);
|
||||
childRight = (child->right)?(1):(0);
|
||||
if (*bfChild < 0) {
|
||||
// child->left > child->right
|
||||
childLeft = childRight - (*bfChild);
|
||||
parentLeft = childLeft + 1 - bfParent;
|
||||
if (heightDiff)
|
||||
*heightDiff = _max(childRight, _max(childLeft, parentLeft)+1) - (childLeft + 1);
|
||||
|
||||
} else {
|
||||
// child->left <= child->right
|
||||
childRight = childLeft + (*bfChild);
|
||||
parentLeft = childRight + 1 - bfParent;
|
||||
if (heightDiff)
|
||||
*heightDiff = _max(childRight, _max(childLeft, parentLeft)+1) - (childRight + 1);
|
||||
|
||||
}
|
||||
*bfChild = childRight - (_max(childLeft, parentLeft) + 1);
|
||||
set_bf(parent, childLeft - parentLeft);
|
||||
|
||||
parent->right = child->left;
|
||||
if (child->left)
|
||||
set_parent(child->left, parent);
|
||||
child->left = parent;
|
||||
set_parent(child, get_parent(parent));
|
||||
set_parent(parent, child);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
static inline Node* RL(Node* parent, int bfParent) {
|
||||
int bfChild, height_delta = 0;
|
||||
Node* child = parent->right;
|
||||
Node* ret;
|
||||
|
||||
if (child->left) {
|
||||
bfChild = get_bf(child->left);
|
||||
parent->right = LL(child, get_bf(child), &bfChild, &height_delta);
|
||||
} else {
|
||||
bfChild = get_bf(child);
|
||||
}
|
||||
|
||||
ret = RR(parent, bfParent+height_delta, &bfChild, nullptr);
|
||||
set_bf(ret, bfChild);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline Node* LR(Node* parent, int bfParent) {
|
||||
int bfChild, height_delta = 0;
|
||||
Node* child = parent->left;
|
||||
Node* ret;
|
||||
|
||||
if (child->right) {
|
||||
bfChild = get_bf(child->right);
|
||||
parent->left = RR(child, get_bf(child), &bfChild, &height_delta);
|
||||
} else {
|
||||
bfChild = get_bf(child);
|
||||
}
|
||||
|
||||
ret = LL(parent, bfParent-height_delta, &bfChild, nullptr);
|
||||
set_bf(ret, bfChild);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void remove(Node *node) {
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
Tree rightSubtree;
|
||||
Node* p = nullptr;
|
||||
Node* current;
|
||||
Node* swap = nullptr;
|
||||
int bf = 0, bfOld;
|
||||
|
||||
rightSubtree.root = node->right;
|
||||
swap = rightSubtree.findSmolest(rightSubtree.root);
|
||||
|
||||
if (swap) {
|
||||
// next exists
|
||||
if (get_parent(swap)) {
|
||||
if (get_parent(swap) != node) {
|
||||
get_parent(swap)->left = swap->right;
|
||||
if (swap->right)
|
||||
set_parent(swap->right, get_parent(swap));
|
||||
}
|
||||
}
|
||||
if (get_parent(node)) {
|
||||
// replace node by next
|
||||
if (get_parent(node)->left == node) {
|
||||
get_parent(node)->left = swap;
|
||||
} else {
|
||||
get_parent(node)->right = swap;
|
||||
}
|
||||
}
|
||||
|
||||
// re-link pointers
|
||||
if (node->right != swap) {
|
||||
swap->right = node->right;
|
||||
if (node->right) set_parent(node->right, swap);
|
||||
current = get_parent(swap);
|
||||
bf = 1;
|
||||
}else{
|
||||
current = swap;
|
||||
bf = -1;
|
||||
}
|
||||
|
||||
swap->left = node->left;
|
||||
if (node->left) set_parent(node->left, swap);
|
||||
set_parent(swap, get_parent(node));
|
||||
|
||||
// inherit nodes balance factor
|
||||
set_bf(swap, get_bf(node));
|
||||
|
||||
} else {
|
||||
// there's no right subTree
|
||||
p = get_parent(node);
|
||||
if (p) {
|
||||
if (p->left == node) {
|
||||
p->left = node->left;
|
||||
bf = 1;
|
||||
} else {
|
||||
p->right = node->left;
|
||||
bf = -1;
|
||||
}
|
||||
}
|
||||
if (node->left)
|
||||
set_parent(node->left, p);
|
||||
|
||||
current = get_parent(node);
|
||||
}
|
||||
|
||||
// reset root
|
||||
if (root == node) {
|
||||
root = swap;
|
||||
if (!swap) {
|
||||
if (node->left) root = node->left;
|
||||
}
|
||||
}
|
||||
|
||||
// balancing
|
||||
while(current) {
|
||||
p = get_parent(current);
|
||||
if (p) {
|
||||
// if parent exists
|
||||
bfOld = get_bf(current);
|
||||
|
||||
if (p->right == current) {
|
||||
current = balanceTree(current, bf);
|
||||
p->right = current;
|
||||
}else {
|
||||
current = balanceTree(current, bf);
|
||||
p->left = current;
|
||||
}
|
||||
|
||||
// bf for parent
|
||||
if (!current->left && !current->right) {
|
||||
// leaf
|
||||
if (p->left == current) bf = 1;
|
||||
else bf = -1;
|
||||
} else {
|
||||
// index
|
||||
bf = 0;
|
||||
if (_abs(bfOld) > _abs(get_bf(current))) {
|
||||
if (p->left == current) bf = 1;
|
||||
else bf = -1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if(current == root){
|
||||
root = balanceTree(root, bf);
|
||||
break;
|
||||
}
|
||||
if (bf == 0) break;
|
||||
|
||||
current = p;
|
||||
}
|
||||
rightSubtree.root = nullptr;
|
||||
node->left = nullptr;
|
||||
node->right = nullptr;
|
||||
// delete node;
|
||||
saveEmptyNode(node);
|
||||
--treeSize;
|
||||
}
|
||||
|
||||
inline Node* findSmolest(Node *n) {
|
||||
if (!n)
|
||||
return nullptr;
|
||||
Node *i = n;
|
||||
for (;i->left; i = i->left);
|
||||
return i;
|
||||
}
|
||||
|
||||
inline void saveEmptyNode(Node *n) {
|
||||
#ifdef NODE_REUSE
|
||||
stack.push(n);
|
||||
#else
|
||||
delete n;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline Node* getEmptyNode(T value) {
|
||||
#ifdef NODE_REUSE
|
||||
if (stack.empty())
|
||||
return new Node(value);
|
||||
auto ret = stack.pop();
|
||||
ret->data = value;
|
||||
return ret;
|
||||
#else
|
||||
return new Node(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
Loading…
Reference in New Issue