Skip to content
Snippets Groups Projects
Commit a787f2a0 authored by Jonas Seidel's avatar Jonas Seidel
Browse files

Biased Trees (Bent Sleator Tarjan 1985) minimal viable

parents
No related branches found
No related tags found
No related merge requests found
*.o
biased_test
Makefile 0 → 100644
CXXFLAGS = -O0 -g -std=c++2a -Wall -Wextra -Wpedantic
biased_test: tree_test.o
$(CXX) $(CXXFLAGS) -o $@ $^
tree_test.o: tree_test.cpp biased_binary_tree.o
$(CXX) $(CXXFLAGS) -c $<
biased_binary_tree.o: biased_binary_tree.cpp biased_binary_tree.h biased_binary_node.o
$(CXX) $(CXXFLAGS) -c $<
biased_binary_node.o: biased_binary_node.cpp biased_binary_node.h
$(CXX) $(CXXFLAGS) -c $<
clean:
rm -f *.o biased_test
.PHONY: clean
#ifndef BIASED_BINARY_NODE_CPP
#define BIASED_BINARY_NODE_CPP
#include "biased_binary_node.h"
template <typename T>
T& BiasedBinaryNode<T>::value(){
return this->_value;
}
template <typename T>
size_t& BiasedBinaryNode<T>::rank(){
return this->_rank;
}
template <typename T>
std::weak_ptr<BiasedBinaryNode<T>>& BiasedBinaryNode<T>::parent(){
return this->_parent;
}
template <typename T>
std::shared_ptr<BiasedBinaryNode<T>>& BiasedBinaryNode<T>::left_child(){
return this->_left_child;
}
template <typename T>
std::shared_ptr<BiasedBinaryNode<T>>& BiasedBinaryNode<T>::right_child(){
return this->_right_child;
}
template <typename T>
std::shared_ptr<BiasedBinaryNode<T>> BiasedBinaryNode<T>::me(){
return this->shared_from_this();
}
template <typename T>
bool BiasedBinaryNode<T>::is_left_child(){
std::shared_ptr<BiasedBinaryNode<T>> parent_lock = this->parent().lock();
if(parent_lock == nullptr) return false;
return this->me() == parent_lock->left_child();
}
template <typename T>
BiasedBinaryNode<T>::BiasedBinaryNode(unsigned long rank) : _rank(rank){}
template <typename T>
BiasedBinaryNode<T>::~BiasedBinaryNode(){
std::cout << "A node has been destroyed!" << std::endl;
}
template <typename T>
void BiasedBinaryNode<T>::rewire_right_child_with(std::shared_ptr<BiasedBinaryNode<T>> new_child){
#ifdef DEBUG
if(this->right_child() != nullptr){
std::cerr << "\033[31mWarning: Some Nodes may have been orphaned\033[39m" << std::endl;
}
#endif
if(new_child == nullptr){
this->right_child().reset();
}else{
std::shared_ptr<BiasedBinaryNode<T>> parent_lock = new_child->parent().lock();
if(parent_lock != nullptr){
if(new_child->is_left_child()){
parent_lock->left_child().reset();
}else{
parent_lock->right_child().reset();
}
}
this->right_child() = new_child;
new_child->parent() = this->me();
}
}
template <typename T>
void BiasedBinaryNode<T>::rewire_left_child_with(std::shared_ptr<BiasedBinaryNode<T>> new_child){
if(this->left_child() != nullptr){
#ifdef DEBUG
std::cerr << "\033[31mWarning: Some Nodes may have been orphaned\033[39m" << std::endl;
#endif
this->left_child()->parent().reset();
}
if(new_child == nullptr){
this->left_child().reset();
}else{
std::shared_ptr<BiasedBinaryNode<T>> parent_lock = new_child->parent().lock();
if(parent_lock != nullptr){
if(new_child->is_left_child()){
parent_lock->left_child().reset();
}else{
parent_lock->right_child().reset();
}
}
this->left_child() = new_child;
new_child->parent() = this->me();
}
}
template <typename T>
void BiasedBinaryNode<T>::replace_with(std::shared_ptr<BiasedBinaryNode<T>> new_node){
std::shared_ptr<BiasedBinaryNode<T>> parent_lock = this->parent().lock();
if(parent_lock == nullptr){
parent_lock.reset();
}else if(this->is_left_child()){
parent_lock->rewire_left_child_with(new_node);
}else{
parent_lock->rewire_right_child_with(new_node);
}
}
template <typename T>
std::shared_ptr<BiasedBinaryNode<T>> BiasedBinaryNode<T>::tilt_left(){
if(this->right_child() == nullptr) return this->me(); // unsure about case
if(this->right_child()->rank() == this->rank() && this->left_child()->rank() == this->rank()){
this->rank()++;
return this->me();
}else if(this->right_child()->rank() == this->rank() && this->left_child()->rank() < this->rank()){
#ifdef PROTOCOL
std::cout << "executing left rotation" << std::endl;
#endif
std::weak_ptr<BiasedBinaryNode<T>> old_parent = this->parent();
std::shared_ptr<BiasedBinaryNode<T>> new_root = this->right_child();
this->rewire_right_child_with(this->right_child()->left_child());
new_root->rewire_left_child_with(this->me());
new_root->parent() = old_parent;
return new_root;
}
return this->me();
}
template <typename T>
std::shared_ptr<BiasedBinaryNode<T>> BiasedBinaryNode<T>::tilt_right(){
if(this->right_child()->rank() == this->rank() && this->left_child()->rank() == this->rank()){
this->rank()++;
return this->me();
}else if(this->right_child()->rank() < this->rank() && this->left_child()->rank() == this->rank()){
#ifdef PROTOCOL
std::cout << "executing right rotation" << std::endl;
#endif
std::weak_ptr<BiasedBinaryNode<T>> old_parent = this->parent();
std::shared_ptr<BiasedBinaryNode<T>> new_root = this->left_child();
this->rewire_left_child_with(this->left_child()->right_child());
new_root->rewire_right_child_with(this->me());
new_root->parent() = old_parent;
return new_root;
}
#ifdef DEBUG
std::cerr << "\033[31mError: no case applicable\033[39m" << std::endl;
assert(1==0);
#endif
}
template <typename T>
bool BiasedBinaryNode<T>::is_leaf(){
if(right_child() == nullptr && left_child() == nullptr){
return true;
}
return false;
}
template <typename T>
std::shared_ptr<BiasedBinaryNode<T>> BiasedBinaryNode<T>::local_join(std::shared_ptr<BiasedBinaryNode<T>> other){
if(other == nullptr){
return this->me();
}else if(this->rank() == other->rank() || (this->rank() > other->rank() && other->is_leaf()) || (this->rank() < other->rank() && this->is_leaf())){
std::shared_ptr<BiasedBinaryNode<T>> new_common_parent = std::make_shared<BiasedBinaryNode<T>>(std::max(this->rank(), other->rank())+1);
new_common_parent->rewire_left_child_with(this->me());
new_common_parent->rewire_right_child_with(other);
return new_common_parent;
}else if(this->rank() > other->rank() && !this->is_leaf()){
std::shared_ptr<BiasedBinaryNode<T>> temporary = this->tilt_left();
this->rewire_right_child_with(temporary.right_child() == nullptr ? other : &temporary.right_child()->local_join(other));
return temporary;
}else
#ifdef DEBUG
if(this->rank() < other->rank() && !other->is_leaf())
#endif
{
BiasedBinaryNode<T> temporary = other.tilt_right();
other->rewire_left_child_with(temporary.left_child() == nullptr ? other : &temporary.left_child()->local_join(this));
return temporary;
}
#ifdef DEBUG
else{
std::cerr << "\033[31mError: no case applicable\033[39m" << std::endl;
assert(0==1);
}
#endif
}
template <typename T>
void BiasedBinaryNode<T>::split_at(BiasedBinaryNode<T>& split_pos,std::shared_ptr<BiasedBinaryNode<T>> before, std::shared_ptr<BiasedBinaryNode<T>> after){
#ifdef DEBUG
assert(split_pos.left_child() == nullptr && split_pos.right_child() == nullptr);
#endif
std::shared_ptr<BiasedBinaryNode<T>> parent_lock = split_pos.parent().lock();
if(parent_lock == nullptr){
return;
}else if(split_pos.is_left_child()){
if(parent_lock->right_child() != nullptr){
after = parent_lock->right_child()->local_join(after);
}
parent_lock->left_child() == nullptr;
}else{
if(parent_lock->left_child() != nullptr){
before = parent_lock->left_child()->local_join(before);
}
parent_lock->right_child() == nullptr;
}
split_at(*parent_lock,before, after);
}
template <typename T>
std::shared_ptr<BiasedBinaryNode<T>> BiasedBinaryNode<T>::global_join(std::shared_ptr<BiasedBinaryNode<T>> other){
#ifdef PROTOCOL
std::cout << *this << std::endl;
std::cout << *other << std::endl;
#endif
if(other == nullptr){
return this->me();
}else if((this->rank() >= other->rank() && this->is_leaf()) || (this->rank() <= other->rank() && other->is_leaf())){
#ifdef PROTOCOL
std::cout << "Case 1" << std::endl;
#endif
std::weak_ptr<BiasedBinaryNode<T>> old_parent = this->parent();
std::shared_ptr<BiasedBinaryNode<T>> new_common_parent = std::make_shared<BiasedBinaryNode<T>>(std::max(this->rank(), other->rank())+1);
new_common_parent->rewire_left_child_with(this->me());
new_common_parent->rewire_right_child_with(other);
new_common_parent->parent() = old_parent;
return new_common_parent;
}else if(this->rank() > other->rank() && !this->is_leaf()){ // is the paper wrong in that it should be <?
#ifdef PROTOCOL
std::cout << "Case 2" << std::endl;
#endif
std::shared_ptr<BiasedBinaryNode<T>> temporary = this->tilt_left();
temporary->rewire_right_child_with(temporary->right_child() == nullptr ? other : temporary->right_child()->global_join(other));
return temporary;
}else if(this->rank() < other->rank() && !other->is_leaf()){
#ifdef PROTOCOL
std::cout << "Case 3" << std::endl;
#endif
std::shared_ptr<BiasedBinaryNode<T>> temporary = other->tilt_right();
temporary->rewire_left_child_with(temporary->left_child() == nullptr ? this->me() : temporary->left_child()->global_join(this->me()));
return temporary;
}else if(this->rank() == other->rank() && (!this->is_leaf() && !other->is_leaf())){
#ifdef PROTOCOL
std::cout << "Case 4" << std::endl;
#endif
std::shared_ptr<BiasedBinaryNode<T>> temporary_u = this->me();
if(this->right_child() != nullptr && this->right_child()->rank() >= this->rank()){
temporary_u = this->right_child();
}
std::shared_ptr<BiasedBinaryNode<T>> temporary_v = other;
if(this->left_child() != nullptr && this->left_child()->rank() >= this->rank()){
temporary_v = this->left_child();
}
std::shared_ptr<BiasedBinaryNode<T>> temporary_z = (temporary_u->right_child() == nullptr ? temporary_v->left_child() : temporary_u->right_child()->global_join(temporary_v->left_child()->me()));
// we note that global_join is defined such that currently temporary_z may be is child of temporary_u->right_child()
if(temporary_z->rank() == this->rank()){
#ifdef PROTOCOL
std::cout << "Case 4a" << std::endl;
#endif
temporary_u->rewire_right_child_with(temporary_z->left_child());
temporary_v->rewire_left_child_with(temporary_z->right_child());
temporary_z->rewire_left_child_with(this->me());
temporary_z->rewire_right_child_with(other);
temporary_z->rank() = std::max(this->rank(),other->rank())+1;
return temporary_z;
}else if(temporary_z->rank() < this->rank()){
#ifdef PROTOCOL
std::cout << "Case 4b" << std::endl;
#endif
if(temporary_u == this->right_child()){
#ifdef PROTOCOL
std::cout << "Case 4b(i)" << std::endl;
#endif
this->rewire_right_child_with(temporary_u->left_child());
temporary_v->rewire_left_child_with(temporary_z);
temporary_u->rewire_left_child_with(this->me());
temporary_u->rewire_right_child_with(other);
temporary_u->rank() = std::max(this->rank(),other->rank())+1;
return temporary_u;
}else if(temporary_v == other->left_child()){
#ifdef PROTOCOL
std::cout << "Case 4b(ii)" << std::endl;
#endif
other->rewire_left_child_with(temporary_v->right_child());
temporary_u->rewire_right_child_with(temporary_z);
temporary_v->rewire_left_child_with(this->me());
temporary_v->rewire_right_child_with(other);
temporary_v->rank() = std::max(this->rank(),other->rank())+1;
return temporary_v;
}else if(temporary_u == this->me() && this->rank() == this->left_child()->rank()){
#ifdef PROTOCOL
std::cout << "Case 4b(iii)" << std::endl;
#endif
temporary_v->rewire_left_child_with(temporary_z);
this->rewire_right_child_with(other);
this->rank() = this->rank()+1;
return this->me();
}else if(temporary_v == other && other->rank() == other->right_child()->rank()){
#ifdef PROTOCOL
std::cout << "Case 4b(iv)" << std::endl;
#endif
temporary_u->rewire_right_child_with(temporary_z);
other->rewire_left_child_with(this->me());
other->rank() = other->rank()+1;
return other;
}else
#ifdef DEBUG
if(temporary_u == this->me() && this->rank() > this->left_child()->rank() && temporary_v == other && other->rank() > other->right_child()->rank())
#endif
{
#ifdef PROTOCOL
std::cout << "Case 4b(v)" << std::endl;
#endif
temporary_v->rewire_left_child_with(temporary_z);
this->rewire_right_child_with(other);
return this->me();
}
#ifdef DEBUG
else{
std::cerr << "\033[31mError: no case applicable\033[39m" << std::endl;
assert(false);
}
#endif
}
}
// unreachable
}
template <typename T>
std::ostream& operator<<(std::ostream& os, BiasedBinaryNode<T>& root){
std::queue<std::shared_ptr<BiasedBinaryNode<T>>> current_level;
current_level.push(root.me());
auto print_level = [](std::queue<std::shared_ptr<BiasedBinaryNode<T>>> level) -> std::queue<std::shared_ptr<BiasedBinaryNode<T>>> {
bool active_level = false;
std::queue<std::shared_ptr<BiasedBinaryNode<T>>> next_level;
while(!level.empty()){
if(level.front() == nullptr) {
level.pop();
continue;
}
std::cout << "(" << level.front()->parent().lock() << ", " << level.front()->rank() << ", " << level.front() << ")\t";
next_level.push(level.front()->left_child());
next_level.push(level.front()->right_child());
level.pop();
active_level = true;
}
if(active_level == true) return next_level;
return std::queue<std::shared_ptr<BiasedBinaryNode<T>>>();
};
while(!current_level.empty()){
std::cout << current_level.size();
current_level = print_level(current_level);
os << std::endl;
}
return os;
}
#endif
#ifndef BIASED_BINARY_NODE_H
#define BIASED_BINARY_NODE_H
#include "preprocessor_compilation_control.h"
#include <cstddef>
#include <iostream>
#include <cassert>
#include <algorithm>
#include <memory>
#include <queue>
template <typename T>
class BiasedBinaryNode;
template <typename T>
std::ostream& operator<<(std::ostream&, BiasedBinaryNode<T>&);
template <typename T>
class BiasedBinaryNode : public std::enable_shared_from_this<BiasedBinaryNode<T>>{
private:
T _value;
unsigned long _rank;
std::weak_ptr<BiasedBinaryNode<T>> _parent;
std::shared_ptr<BiasedBinaryNode<T>> _left_child;
std::shared_ptr<BiasedBinaryNode<T>> _right_child;
std::weak_ptr<BiasedBinaryNode<T>>& parent();
std::shared_ptr<BiasedBinaryNode<T>>& left_child();
std::shared_ptr<BiasedBinaryNode<T>>& right_child();
std::shared_ptr<BiasedBinaryNode<T>> tilt_right();
std::shared_ptr<BiasedBinaryNode<T>> tilt_left();
std::shared_ptr<BiasedBinaryNode<T>> local_join(std::shared_ptr<BiasedBinaryNode<T>>);
public:
BiasedBinaryNode(unsigned long);
~BiasedBinaryNode();
friend std::ostream& operator<<<>(std::ostream&, BiasedBinaryNode<T>&);
std::shared_ptr<BiasedBinaryNode<T>> me();
bool is_leaf();
bool is_left_child();
T& value();
size_t& rank();
void rewire_right_child_with(std::shared_ptr<BiasedBinaryNode<T>>);
void rewire_left_child_with(std::shared_ptr<BiasedBinaryNode<T>>);
void replace_with(std::shared_ptr<BiasedBinaryNode<T>>);
void split_at(BiasedBinaryNode<T>& split_pos,std::shared_ptr<BiasedBinaryNode<T>> before, std::shared_ptr<BiasedBinaryNode<T>> after);
std::shared_ptr<BiasedBinaryNode<T>> global_join(std::shared_ptr<BiasedBinaryNode<T>>);
};
#include "biased_binary_node.cpp"
#endif
#ifndef BIASED_BINARY_TREE_CPP
#define BIASED_BINARY_TREE_CPP
#include "biased_binary_tree.h"
template <typename T>
BiasedBinaryTree<T>::BiasedBinaryTree(std::shared_ptr<BiasedBinaryNode<T>> root) : _root(root){}
template <typename T>
std::shared_ptr<BiasedBinaryNode<T>>& BiasedBinaryTree<T>::root(){
return this->_root;
}
template <typename T>
void BiasedBinaryTree<T>::join(BiasedBinaryTree<T> other){
if(this->root() != nullptr){
this->root() = this->root()->global_join(other.root());
}else{
this->root() = other.root();
}
other.root() = std::shared_ptr<BiasedBinaryNode<T>>();
}
template <typename T>
std::ostream& operator<<(std::ostream& os, BiasedBinaryTree<T>& tree){
if(tree.root() != nullptr) os << *tree.root();
return os;
}
#endif
#ifndef BIASED_BINARY_TREE_H
#define BIASED_BINARY_TREE_H
#include "biased_binary_node.h"
template <typename T>
class BiasedBinaryTree;
template <typename T>
std::ostream& operator<<(std::ostream&, BiasedBinaryTree<T>&);
template <typename T>
class BiasedBinaryTree{
std::shared_ptr<BiasedBinaryNode<T>> _root;
public:
BiasedBinaryTree(){}
BiasedBinaryTree(std::shared_ptr<BiasedBinaryNode<T>>);
friend std::ostream& operator<<<>(std::ostream&, BiasedBinaryTree<T>&);
std::shared_ptr<BiasedBinaryNode<T>>& root();
void join(BiasedBinaryTree<T>);
};
#include "biased_binary_tree.cpp"
#endif
#ifndef PREPROCESSOR_COMPILATION_CONTROL_H
#define PREPROCESSOR_COMPILATION_CONTROL_H
/*
Define DEBUG for evaluation of assertions
*/
#define DEBUG
/*
Define for Protocol of join and split cases
*/
#define PROTOCOL
#endif
#include "biased_binary_tree.h"
#include <vector>
#include <iostream>
int main(){
BiasedBinaryTree<int> start (std::make_shared<BiasedBinaryNode<int>>(5));
for(int i = 1; i < 5; i++){
std::cout << "joining " << i << std::endl;
start.join(BiasedBinaryTree(std::make_shared<BiasedBinaryNode<int>>(2)));
}
BiasedBinaryTree<int> second (std::make_shared<BiasedBinaryNode<int>>(5));
for(int i = 1; i < 5; i++){
std::cout << "joining " << i << std::endl;
second.join(BiasedBinaryTree(std::make_shared<BiasedBinaryNode<int>>(i)));
}
start.join(second);
std::cout << "----------------" << std::endl;
std::cout << start;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment