This commit is contained in:
hladu357 2024-03-08 14:01:12 +01:00
commit 33b21e79af
1 changed files with 579 additions and 0 deletions

579
avl.cpp Normal file
View File

@ -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
}
};