Files
secondo/Algebras/MainMemory2/ttree.h
2026-01-23 17:03:45 +08:00

1813 lines
39 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2016,
University in Hagen,
Faculty of Mathematics and Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
*/
#ifndef TTREE_H
#define TTREE_H
#include <assert.h>
#include <cstdlib>
#include <utility>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#include "MainMemoryExt.h"
namespace ttree{
/*
0. Forward declaration of the TTree class
*/
template <class U, class Comp>
class TTree;
/*
1 class TTreeNode
The class TTreeNode is a class for the nodes of an t-tree.
*/
template<class T, class Comparator>
class TTreeNode{
template<class U,class Comp> friend class TTree;
public:
/*
1.1 Constructor
This constructor initializes all members
*/
// creates a new T-Tree node
TTreeNode(const size_t _minEntries, const size_t _maxEntries):
minEntries(_minEntries), maxEntries(_maxEntries),
left(0), right(0), count(0), height(0) {
objects = new T*[TTreeNode<T,Comparator>::maxEntries];
for(size_t i=0;i<TTreeNode<T,Comparator>::maxEntries;i++){
objects[i] = 0;
}
}
/*
1.2 Copy constructor
Creates a depth copy of this node.
*/
TTreeNode(const TTreeNode<T,Comparator>& source):
objects(source.objects), left(0), right(0), height(source.height){
this->left =
source.left==NULL?NULL:new TTreeNode<T,Comparator>(*source.left);
this->right =
source.right==NULL?NULL:new TTreeNode<T,Comparator>(*source.right);
}
/*
1.3 Assignment Operator
*/
TTreeNode<T,Comparator>& operator=(const TTreeNode<T,Comparator>& source) {
this->objects = source.objects;
this->left = source.left
? new TTreeNode<T,Comparator>(source.left)
:NULL;
this->right = source.right
? new TTreeNode<T,Comparator>(source.right)
:NULL;
this->height = source.height;
return *this;
}
/*
1.4 Destructor
Destroy the subtree rooted by this node
*/
~TTreeNode() {
for(size_t i=0; i<count; i++) {
delete objects[i];
}
delete[] objects;
if(left) delete left;
if(right) delete right;
left = NULL;
right = NULL;
}
/*
1.5 Methods
~isLeaf~
This function returns true if this node represents a leaf.
*/
inline bool isLeaf() const {
if(left || right)
return false;
return true;
}
/*
~memSize~
Returns the amount of memory occupied by the subtree represented by this node.
*/
size_t memSize() const {
size_t res = sizeof(*this) +
sizeof(void*) * TTreeNode<T,Comparator>::maxEntries;
for(int i=0;i<count;i++){
res += sizeof(* objects[i]);
}
if(left)
res += left->memSize();
if(right)
res += right->memSize();
return res;
}
/*
~getObject~
Returns the content of this node at position i.
*/
T* getObject(const int i) const {
return objects[i];
}
/*
~getMinEntries~
Return the minimum number of entries of this node.
*/
inline size_t getMinEntries() const{
return minEntries;
}
/*
~getMaxEntries~
Returns the capacity of this node.
*/
inline int getMaxEntries() const{
return maxEntries;
}
/*
~getCount~
Returns the number of entries of this node.
*/
inline size_t getCount() const{
return count;
}
/*
~getLeftSon~
Returns the parent of this node or 0 if this node is the root of the tree.
*/
inline TTreeNode<T,Comparator>* getLeftSon(){
return left;
}
/*
~getRightSon~
Returns the parent of this node or 0 if this node is the root of the tree.
*/
inline TTreeNode<T,Comparator>* getRightSon(){
return right;
}
/*
~clear~
Removes the entries from this node. If deleteContent is set to be
true, the sons of this node are destroyed.
*/
void clear(const bool deleteContent) {
for(size_t i=0;i<count;i++) {
if(deleteContent){
delete objects[i];
}
objects[i] = 0;
}
if(deleteContent) {
if(left)
delete left;
if(right)
delete right;
}
left = 0;
right = 0;
height=0;
count = 0;
}
/*
~updateHeight~
Computes the height of this node from the height of
the sons. This method should be called whenever the
sons are changed. Note that only the direct descendants
are used to compute the new height.
*/
void updateHeight() {
int h1 = left==NULL?0:left->height+1;
int h2 = right==NULL?0:right->height+1;
height = std::max(h1,h2);
}
/*
~balance~
Computes the balance of this node.
*/
int balance()const{
int h1 = 0;
int h2 = 0;
if(left)
h1 = left?left->height+1:0;
if(right)
h2 = right?right->height+1:0;
return h1-h2;
}
/*
~print~
write a textual representation for this node to ~out~.
*/
std::ostream& print(std::ostream& out) const{
out << "(";
for(int i=0; i<count; i++) {
out << i << ":" << " '" << *objects[i] <<"' ";
}
out << ")";
return out;
}
/*
~printtree~
Print the tree rooted by this in tree format.
*/
void printtree(std::ostream& out) const{
printtree(this,out);
}
/*
~getMinValue~
Returns the minimum value of a non-empty node.
*/
inline const T& getMinValue()const{
assert(count>0);
return *(objects[0]);
}
/*
~getMaxValue~
Returns the maximum value of a non-empty node.
*/
inline const T& getMaxValue()const{
assert(count>0);
return *(objects[count-1]);
}
/*
~hasSpace~
The function checks whether the node can include a further entry.
*/
inline bool hasSpace() const{
return count < maxEntries; //-1;
}
/*
~insert~
Inserts a new entry into a node having enough space.
The new entry should be created exclusively for the tree,
this method does not create a copy from it.
*/
void insert(T* value, std::vector<int>* attrPos){
assert(hasSpace());
// search insertion position
size_t pos = 0;
while( (pos < count)
&&!Comparator::greater( *objects[pos],*value,attrPos)){
pos++;
}
for(size_t i = count ; i > pos; i--){
objects[i] = objects[i-1];
}
objects[pos] = value;
count++;
}
/*
~replaceGreatest~
Replaces the last element of this node with a new value. The old
last element is returned. If the node is empty, null is returned.
*/
T* replaceGreatest(T* newValue, std::vector<int>* attrPos){
T* res;
if(count==0){
res = 0;
} else {
// remove the greatest object
res = objects[count-1];
objects[count-1] = 0;
count--;
}
insert(newValue,attrPos);
return res;
}
/*
~checkCount~
This is a pure debugging function checking whether each node in the
tree rooted by this contains a valid number of entries.
*/
bool checkCount(std::ostream& out) const{
if(count==0){
out << "found node without elements" << endl;
return false;
}
if(count > maxEntries){
out << "found node having more entries than allowed" << endl;
}
if(left && right){ // inner node
if(count < minEntries){
out << "found inner node having too less entries" << endl;
return false;
}
}
bool ok = true;
if(left){
ok = ok && left->checkCount(out);
}
if(right){
ok = ok && right->checkCount(out);
}
return ok;
}
/*
~checkOrder~
checks whether the tree rooted by this has a valid ordering.
*/
bool checkOrder(std::vector<int>* attrPos, std::ostream& out)const{
return checkOrder(0,0,attrPos, out);
}
/*
~checkHalfLeaf~
Checks whether this has exactly one son.
*/
inline bool isHalfLeaf() const{
return ((left==0) && (right!=0)) || ((left!=0) && (right==0));
}
/*
~hasSpaceFor~
Checks whether this has enough space for including the
entries of rhs.
*/
inline bool hasSpaceFor(TTreeNode<T,Comparator>* rhs) const{
assert(rhs);
assert(this);
return count + rhs->count <= maxEntries;
}
/*
~merge~
Moves the entries from right to left. The pointers of the parameters
will be destroyed by this function. This is only possible, if
one of the arguments is a leaf and the only son of the other parameter.
*/
static TTreeNode<T,Comparator>* merge(TTreeNode<T,Comparator>* left,
TTreeNode<T,Comparator>* right,
std::vector<int>* attrPos){
assert(left);
assert(right);
assert(left!=right);
if(left == right->left){
assert(!right->right);
assert(left->isLeaf());
right->decouple();; // disconnect nodes
} else if(right == left->right){
assert(!left->left);
assert(right->isLeaf());
left->decouple();
} else {
assert(false);
}
assert(left->hasSpaceFor(right));
for(size_t i=0;i<right->count; i++){
left->objects[left->count] = right->objects[i];
left->count++;
right->objects[i] = 0;
}
TTreeNode<T,Comparator>* res = left;
left = 0;
right->count = 0;
delete right;
right = 0;
return res;
}
/*
~remove~
Removes an entry from this node. If the entry is not present,
false is returned. The removed object will be returned in
parameter object.
*/
bool remove(T& value, std::vector<int>* attrPos){
int index = find(value,attrPos);
if(!Comparator::equal(value, *objects[index],attrPos)){
return false;
}
delete objects[index];
count--;
for(size_t i=index; i<count; i++){
objects[i] = objects[i+1];
}
objects[count] = 0;
return true;
}
/*
~deleteMin~
Removes the minimum element of a node. The element is returned, not destroyed.
*/
T* deleteMin(){
assert(count>0);
T* res = objects[0];
count--;
for(size_t i=0;i<count; i++){
objects[i] = objects[i+1];
}
objects[count] = 0;
return res;
}
TTreeNode<T,Comparator>* clone(){
TTreeNode<T,Comparator>* res;
res = new TTreeNode<T,Comparator>(minEntries, maxEntries);
if(left){
res->left = left->clone();
}
if(right){
res->right = right->clone();
}
res->count = count;
res->height = height;
for(size_t i=0;i<count;i++){
T* src = objects[i];
res->objects[i] = new T(*src);
}
return res;
}
protected:
/*
1.6 Member variables
*/
size_t minEntries;
size_t maxEntries;
TTreeNode<T,Comparator>* left;
TTreeNode<T,Comparator>* right;
size_t count;
size_t height;
T** objects;
/*
~find~
Searches for a specified element within this node using a binary search.
Returns the index where the element is or should be.
*/
int find(const T& value, const std::vector<int>* attrPos)const{
int min = 0;
int max = count-1;
while(min < max){
int mid = (min + max) / 2;
if(Comparator::equal(value,*objects[mid],attrPos)){
return mid;
}
if(Comparator::smaller(value,*objects[mid], attrPos)){
max = mid - 1;
} else {
min = mid + 1;
}
}
return min;
}
/*
~decouple~
Decouples any child from this node.
*/
void decouple(){
left=0;
right=0;
height=0;
}
/*
~printtree~
Support function.
*/
static void printtree(const TTreeNode<T,Comparator>* root,
std::ostream& out, bool isRoot = true){
if(isRoot){
out << "( tree ";
}
if(!root){
out << "' '" << endl;
} else {
out << "(";
out << "'";
for(size_t i=0;i<root->getCount();i++){
if(i>0) out << ", ";
out << *(root->getObject(i));
}
out << "' ";
printtree(root->left,out,false);
printtree(root->right,out, false);
out << " )";
}
if(isRoot){
out << ")";
out << endl;
}
}
/*
~checkOrder~
Support function.
*/
bool checkOrder(const T* min, const T* max, std::vector<int>* attrPos,
std::ostream& out) const{
// check internal order
for(size_t i=0;i<count-1; i++){
if(Comparator::greater(*objects[i], *objects[i+1],attrPos)){
out << "found invalid order within a single node" << endl;
return false;
}
}
if(min && Comparator::smaller(getMinValue(),*min, attrPos) ){
out << "found value of a node smaller than allowed" << endl;
return false;
}
if(max && Comparator::greater(getMaxValue(), *max, attrPos)){
out << "found value of a node greater than allowed" << endl;
return false;
}
bool ok = true;
if(left){
ok = ok && left->checkOrder(min, objects[0], attrPos,out);
}
if(right){
ok = ok && right->checkOrder(objects[count-1], max, attrPos,out);
}
return ok;
}
};
/*
2 Class Iterator
This inner class provides an iterator for sorted iterating
trough the tree.
*/
template<class T, class Comparator>
class Iterator{
public:
Iterator():stack(),pos(0){}
/*
2.1 Constructors
Creates an iterator for the given tree. The position
is set to the smallest entry in the tree.
*/
Iterator(TTreeNode<T,Comparator>* root) {
TTreeNode<T,Comparator>* son = root;
while(son){
stack.push(son);
son = son->getLeftSon();
}
pos = 0;
}
/*
2.2 Tail constructor
Creates a constructor for a tree using a
minimum value.
*/
Iterator(TTreeNode<T,Comparator>* root,
const T& minV,
const std::vector<int>* vec = 0){
TTreeNode<T,Comparator>* son = root;
pos = 0;
while(son){
if(Comparator::smaller(minV,son->getMinValue(),vec)){
// value smaller than all entries
stack.push(son);
son = son->getLeftSon();
} else if(Comparator::greater(minV,son->getMaxValue(),vec)){
// value greater than all entries
son = son->getRightSon();
} else {
// value is inside the node
stack.push(son);
while(pos<son->getCount()){
if(!Comparator::smaller(*(son->getObject(pos)),minV,vec)){
return;
}
pos++;
}
// should never be reached
}
}
}
/*
2.2 Copy Contructor
*/
Iterator(const Iterator& it){
this->stack = it.stack;
this->pos = it.pos;
}
/*
2.2 Assignment Operator
*/
Iterator& operator=(const Iterator& it){
this->stack = it.stack;
this->pos = it.pos;
return *this;
}
/*
2.3 Increment operator
This operator sets this iterator to the next position
in the tree.
*/
Iterator& operator++(int){
next();
return *this;
}
/*
2.4 Dereference operator
This operator returns the element currently under the
iterator's cursor. If no more elements exist, NULL
is returned.
*/
T operator*() {
assert(!stack.empty());
const TTreeNode<T,Comparator>* elem = stack.top();
assert(elem);
assert(pos < elem->getCount());
return *(elem->getObject(pos));
}
/*
~next~
The ~next~ function sets the iterator to the next element.
If no more elements are available, the result will be __false__
otherwise __true__.
*/
bool next(){
if(stack.empty()){
return false;
}
// there are elemnts in the node left
TTreeNode<T,Comparator>* elem = stack.top();
if(pos < elem->getCount()-1) {
pos++;
return true;
}
stack.pop(); // the current node is processed
pos = 0; // try to find an unprocessed node
// go to first element in next node
TTreeNode<T,Comparator>* son;
if((son = elem->getRightSon())) {
stack.push(son);
while((son = son->getLeftSon())){
stack.push(son);
}
return true;
} else { // there is no right son
return !stack.empty();
}
}
/*
~hasNext~
This function checks whether after the current element
further elements exist.
*/
bool hasNext() const{
int size = stack.size();
if(size==0){ // no elements
return false;
}
if(size>1){ // at least one nn processed node
return true;
}
TTreeNode<T,Comparator>* elem = stack.top();
if(pos < elem->getCount()-1){ // node has unprocessed elements
return true;
}
return (elem->getRightSon()!=0);
}
/*
~end~
The ~end~ function checks whether the iterator does not have
any elements, i.e. whether Get or [*] would return NULL.
*/
bool end() const{
return stack.empty();
}
private:
std::stack<TTreeNode<T,Comparator>*> stack;
size_t pos;
};
/*
3 class TTree
This is the main class of this file. It implements a mainmemory-based TTree.
*/
template<class T, class Comparator>
class TTree {
typedef TTreeNode<T, Comparator> Node;
public:
/*
3.1 Constructor
Creates an empty tree.
*/
TTree(int _minEntries, int _maxEntries):
minEntries(_minEntries), maxEntries(_maxEntries),
root(0), entryCount(0) {}
/*
3.2 Destructor
Destroys this tree.
*/
~TTree(){
if(root!=NULL) {
delete root;
root = NULL;
entryCount = 0;
}
}
/*
3.3 Methods
~begin~
This function creates an iterator which is positioned to the
first element in the tree .
*/
Iterator<T,Comparator> begin() {
Iterator<T,Comparator> it(root);
return it;
}
/*
~tail~
This operator returns an iterator starting at a specified element
instead of the begin.
*/
Iterator<T, Comparator> tail(const T& minV,
const std::vector<int>* attrPos =0){
Iterator<T,Comparator> it(root,minV,attrPos);
return it;
}
const T* GetNearestSmallerOrEqual(const T& v,
const std::vector<int>* attrPos)const{
return getNearestSmallerOrEqual(root,v, attrPos);
}
/*
~noEntries~
Returns the number od entries of this tree.
*/
size_t noEntries() const{
return entryCount;
}
size_t countEntries() const {
return countEntries(root);
}
/*
~isEmpty~
Returns true if this tree is empty.
*/
bool isEmpty() const {
return root==NULL;
}
/*
~memSize~
Returns the memory size of this tree.
*/
size_t memSize() const {
size_t res = sizeof(*this); // size of empty tree
if(root){
res += root->memSize();
}
return res;
}
/*
~print~
Prints this tree to the give ostream.
The format is understood by the tree viewer of Secondo's Javagui.
*/
void Print(std::ostream& out) const {
out << "( tree (" << std::endl;
if(root)
printttree(root, out);
else
out << "empty";
out << "))" << std::endl;
}
void printorel(std::ostream& out) const {
out << "( tree (" << std::endl;
if(root)
printorel(root, out);
else
out << "empty";
out << "))" << std::endl;
}
/*
~update~
Updates a given value in this tree with the second value.
*/
bool update(T& value, T& newValue, std::vector<int>* attrPos){
bool success;
root = update(root,value,newValue,attrPos,success);
return success;
}
bool update(T& value, T& newValue) {
std::vector<int>* attrPos = new std::vector<int>();
attrPos->push_back(1);
attrPos->push_back(2);
bool success = update(root,value,newValue,attrPos,success);
delete attrPos;
return success;
}
/*
~insert~
Adds object ~o~ to this tree.
*/
bool insert(T& value, std::vector<int>* attrPos) {
bool success;
root = insert(root,value,attrPos,success);
root->updateHeight();
return success;
}
bool insert(T& value, int i) {
std::vector<int>* attrPos = new std::vector<int>();
attrPos->push_back(i);
bool success = insert(value,attrPos);
attrPos->clear();
delete attrPos;
return success;
}
bool insert(T& value) {
std::vector<int>* attrPos = new std::vector<int>();
attrPos->push_back(1);
bool success = insert(value,attrPos);
attrPos->clear();
delete attrPos;
return success;
}
/*
~remove~
Removes object ~o~ from this tree.
*/
bool remove(T& value, std::vector<int>* attrPos){
bool success;
if(!root)
return false;
root = remove(root,value,attrPos,success);
if(root) {
root->updateHeight();
}
return success;
}
bool remove(T& value){
bool success;
if(!root) {
return false;
}
std::vector<int>* attrPos = new std::vector<int>();
attrPos->push_back(1);
root = remove(root,value,attrPos,success);
if(root) {
root->updateHeight();
}
delete attrPos;
return success;
}
/*
~clear~
*/
void clear(const bool deleteContent) {
if(root){
root->clear(deleteContent);
entryCount = 0;
}
}
/*
~check~
Checks the structure of the tree
*/
bool Check(std::ostream& out){
if(!root) return true;
return root->checkCount(out) && root->checkOrder(0,out);
}
size_t Size(){
return Size(root);
}
TTree<T,Comparator>* clone(){
TTree<T,Comparator>* res = new TTree(minEntries, maxEntries);
if(root){
res->root = root->clone();
}
res->entryCount = entryCount;
return res;
}
private:
int minEntries;
int maxEntries;
Node* root;
size_t entryCount;
size_t Size(Node* node){
if(!node) return 0;
return Size(node->left) + Size(node->right) + 1;
}
/*
~noEntries~
Computes the height of this node from the height of
the sons. This method should be called whenever the
sons are changed. Note that only the direct descendants
are used to compute the new height.
*/
size_t countEntries(Node* root) {
if(root == 0)
return 0;
return countEntries(root->left)
+ countEntries(root->right)
+ root->count;
}
/*
~insert~
This function inserts __value__ into the subtree given by root.
Duplicates are allowed
It returns the root of the new tree.
*/
Node* insert(Node* root,
T& value,
std::vector<int>* attrPos,
bool& success) {
T* v = new T(value);
Node* res = insert(root,v,attrPos,success);
if(!success){
delete v;
}
return res;
}
Node* insert(Node* root,
T* value,
std::vector<int>* attrPos,
bool& success) {
// leaf reached
if(root == NULL){
root = new Node(minEntries,maxEntries);
root->insert(value, attrPos);
entryCount++;
success = true;
return root;
}
if(root->isLeaf() && root->hasSpace()){
root->insert(value,attrPos);
success = true;
entryCount++;
return root;
}
if( !Comparator::smaller(*value,root->getMinValue(),attrPos)
&& !Comparator::greater(*value,root->getMaxValue(), attrPos)){
// bounding node
if( root->hasSpace()){
// we have space, insert here
root->insert(value,attrPos);
entryCount++;
success = true;
return root;
} else {
// there is no space, replace value with the
// rightmost value in the node
value=root->replaceGreatest(value,attrPos);
}
}
// search in the left subtree
if(!Comparator::greater(*value, root->getMinValue(), attrPos)){
root->left = insert(root->left,value,attrPos,success);
root->updateHeight();
// rotation or double rotation required
if(abs(root->balance()) > 1) {
// single rotation is sufficient
if(root->left->balance() > 0) {
return rotateRight(root);
}
// left-right rotation is required
if(root->left->balance() < 0) {
return rotateLeftRight(root,attrPos);
}
assert(false); // should never be reached
return NULL;
} else { // root remains balanced
return root;
}
assert(false);
}
// search right subtree
if(!Comparator::smaller(*value,root->getMaxValue(),attrPos)) {
root->right = insert(root->right,value,attrPos,success);
root->updateHeight();
// rotation or double rotation required
if(abs(root->balance())>1) {
// single left rotation sufficient
if(root->right->balance() < 0) {
return rotateLeft(root);
}
// right-left rotation required
if(root->right->balance() > 0){
return rotateRightLeft(root,attrPos);
}
assert(false); // should never be reached
success = false;
return NULL;
} else {
return root;
}
}
assert(false);
return 0; // should never be reached
}
/*
~printNodeInfo~
Prints information about a single node.
*/
void printNodeInfo(Node* node) {
std::cout << std::endl << "-->NODE INFO<---------------" << std::endl;
node->print(std::cout);
std::cout << std::endl;
std::cout << "minValue: " << node->minValue << std::endl;
std::cout << "maxValue: " << node->maxValue << std::endl;
std::cout << "count: " << node->count << std::endl;
if(node->isLeaf())
std::cout << "isLeaf: " << "yes" << std::endl;
else
std::cout << "isLeaf: " << "no" << std::endl;
std::cout << "------------------>NODE INFO<--" << std::endl << std::endl;
}
/*
~remove~
This function removes __value__ from the subtree given by root.
Returns the new root of the tree.
*/
Node* remove(Node* root,
T& value,
std::vector<int>* attrPos,
bool& success) {
if(Comparator::smaller(value,root->getMinValue(),attrPos)){
// delete value within the left son of root
if(!root->left){ // value cannot be found
success = false;
return root;
}
root->left = remove(root->left,value,attrPos,success);
if(!success){ // value not found, structure soes not change
return root;
}
root->updateHeight();
if(root->left && !root->right &&
root->hasSpaceFor(root->left)){
// a half leaf having left son
return Node::merge(root->left, root, attrPos);
}
if(abs(root->balance())>1) {
// single left rotation sufficient
if(root->right->balance() <= 0) {
return rotateLeft(root);
}
// right-left rotation required
if(root->right->balance() > 0){
return rotateRightLeft(root,attrPos);
}
assert(false); // should never be reached
return 0;
} else { // balance is ok
return root;
}
assert(false);
}
if(Comparator::greater(value,root->getMaxValue(),attrPos)){
// delete value in the right son of root
if(!root->getRightSon()){
success = false;
return root;
}
root->right = remove(root->right,value,attrPos,success);
if(!success){
return root;
}
root->updateHeight();
if(root->right && !root->left
&& root->hasSpaceFor(root->right)){
return Node::merge(root,root->right, attrPos);
}
// rotation or double rotation required
if(abs(root->balance()) > 1) {
// single rotation is sufficient
if(root->left->balance() >= 0) {
return rotateRight(root);
}
// left-right rotation is required
if(root->left->balance() < 0) {
return rotateLeftRight(root,attrPos);
}
assert(false); // should never be reached
return NULL;
} else {
return root;
}
assert(false);
}
// found bounding node
success = root->remove(value, attrPos);
if(!success){ // value not found, no structure change
return root;
} else {
entryCount--;
}
// handle leaf node
if(root->isLeaf()){
if(root->count==0){
delete root;
return 0;
} else {
return root;
}
}
// handle half leaf
if(root->isHalfLeaf()){
if(root->left){
if(root->hasSpaceFor(root->left) ){
return Node::merge(root->left, root, attrPos);
}
} else if(root->hasSpaceFor(root->right) ){
return Node::merge(root, root->right, attrPos);
}
return root;
}
// root is an inner node
if(root->count >= root->minEntries){ // structure is ok
return root;
}
// remove the minimum value from the right subtree
T* v = deleteMin(root->right, attrPos);
root->insert(v, attrPos);
// because the removed value is inserted again,
// the entryCount is not changed
root->updateHeight();
// handle possible structure changes in right subtree
if(abs(root->balance()) > 1) {
// single rotation is sufficient
if(root->left->balance() >= 0) {
return rotateRight(root);
}
// left-right rotation is required
if(root->left->balance() < 0) {
return rotateLeftRight(root,attrPos);
}
assert(false); // should never be reached
return 0;
} else {
// balance of root is ok
return root;
}
assert(false);
return 0;
}
/*
~deleteMin~
Removes the smallest value of the subtree rooted by root and returns this
value. root is changed too if necessary.
*/
T* deleteMin(Node*& root, std::vector<int>* attrPos){
if(root->left){ // there is a left subtree, minimum value is there
T* res = deleteMin(root->left, attrPos);
root->updateHeight();
if(root->isLeaf()){
// left subtree is 0 now
return res;
}
if(root->isHalfLeaf()){
if(root->left && root->hasSpaceFor(root->left)){
root = Node::merge(root->left, root,attrPos);
return res;
}
if(root->right && root->hasSpaceFor(root->right)){
root=Node::merge(root,root->right, attrPos);
return res;
}
}
// a inner node, may be a balance is required
if(abs(root->balance())>1) {
// single left rotation sufficient
if(root->right->balance() <= 0) {
root = rotateLeft(root);
return res;
}
// right-left rotation required
if(root->right->balance() > 0){
root = rotateRightLeft(root,attrPos);
return res;
}
assert(false); // should never be reached
return 0;
} else { // balance ok
return res;
}
assert(false);
return 0;
}
// now root is either a leaf or a half leaf having a
// right son
T* res = root->deleteMin();
if(root->right && root->hasSpaceFor(root->right) ){
root = Node::merge(root, root->right, attrPos);
return res;
}
if(root->count==0){ // removed the last entry from a leaf
delete root;
root = 0;
}
return res;
}
/*
~update~
This function updates __value__ in the subtree given by root.
*/
Node* update(Node* root,
T& value,
T& newValue,
std::vector<int>* attrPos,
bool& success) {
root = remove(root,value,attrPos,success);
root = insert(root,newValue,attrPos,success);
return root;
}
/*
~rotateRight~
Performs a right rotation in the subtree given by root.
*/
Node* rotateRight(Node* root) {
Node* y = root->left;
Node* B = y->right;
Node* C = root->right;
root->left=B;
root->right=C;
root->updateHeight();
y->right=root;
y->updateHeight();
return y;
}
/*
~rotateRightLeft~
Performs a right-left rotation in the subtree given by root.
*/
Node* rotateRightLeft(Node* root,
std::vector<int>* attrPos) {
Node* x = root;
Node* z = x->right;
Node* y = z->left;
Node* B1 = y->left;
Node* B2 = y->right;
//special case:
//if y is leaf, move entries from z to y till y has the
// minimum number of entries
// y contains smaller values than z, so we have to
// move from the beginning of z to the end of y
if(y->isLeaf() && (y->getCount() < y->getMinEntries())){
size_t entriesToTransfer = y->getMinEntries() - y->getCount();
assert(z->getCount() > entriesToTransfer);
// transfer the entries
for(size_t i=0; i< entriesToTransfer; i++){
y->objects[y->getCount()+i] = z->objects[i];
}
// move entries in z to left
for(size_t i=0; i< z->getCount() - entriesToTransfer; i++){
z->objects[i] = z->objects[i+entriesToTransfer];
} // fill z up with 0
for(size_t i = z->getCount() - entriesToTransfer ;
i< z->getCount(); i++){
z->objects[i] = 0;
}
y->count += entriesToTransfer;
z->count -= entriesToTransfer;
}
x->right=B1;
x->updateHeight();
z->left = B2;
z->updateHeight();
y->left = x;
y->right=z;
y->updateHeight();
return y;
}
/*
~rotateLeft~
Performs a left rotation in the subtree given by root.
*/
Node* rotateLeft(Node* root) {
Node* y = root->right;
Node* B = y->left;
root->right = B;
root->updateHeight();
y->left=root;
y->updateHeight();
return y;
}
/*
~rotateLeftRight~
Performs a left-right rotation in the subtree given by root.
*/
Node* rotateLeftRight(Node* root,
std::vector<int>* attrPos) {
Node* x = root;
Node* z = root->left;
Node* y = z->right;
Node* A = z->left;
Node* B = y->left;
Node* C = y->right;
// special case:
// if y is leaf, move entries from z to y till y is full node
if(y->isLeaf() && (y->getCount() < y->getMinEntries())) {
size_t entriesToMove = y->getMinEntries() - y->getCount();
// create place in the beginning of y
for(size_t i = y->getCount() ; i>0; i--){
y->objects[i+entriesToMove -1] = y->objects[i -1];
}
// move entries from z to y
for(size_t i=0;i<entriesToMove; i++){
size_t z_i = z->getCount() - entriesToMove + i;
y->objects[i] = z->objects[z_i];
z->objects[z_i] = 0;
}
y->count += entriesToMove;
z->count -= entriesToMove;
}
z->left=A;
z->right=B;
z->updateHeight();
x->left=C;
x->updateHeight();
y->left=z;
y->right=x;
y->updateHeight();
return y;
}
/*
~print~
Prints the subtree given by root to the console.
*/
void printttree(const Node* root,
std::ostream& out) const {
if(!root){
out << " 'empty' ";
return;
}
out << " -->ROOT(";
for(int i=0; i<root->count; i++) {
out << i << ":" << " '" << *root->objects[i] <<"' ";
}
out << ") \n";
out << " ----->LEFT(";
printttree(root->left,out);
out << ") \n";
out << " ------->RIGHT(";
printttree(root->right,out);
out << ") \n";
}
void printorel(const Node* root,
std::ostream& out) const {
if(!root){
out << " 'empty' ";
return;
}
out << " -->ROOT(";
for(int i=0; i<root->count; i++) {
out << i << ":" << " '" << **root->objects[i] <<"' ";
}
out << ") \n";
out << " ----->LEFT(";
printorel(root->left,out);
out << ") \n";
out << " ------->RIGHT(";
printorel(root->right,out);
out << ") \n";
}
T const * getNearestSmallerOrEqual(Node* root, const T& v,
const std::vector<int>* attrPos)const{
T const * cand = 0;
while(root){
if(Comparator::smaller(v, root->getMinValue(),attrPos)){
root = root->getLeftSon();
} else if(Comparator::greater(v,root->getMaxValue(),attrPos)){
cand = &root->getMaxValue();
root = root->getRightSon();
} else {
int index = root->find(v, attrPos);
if(!Comparator::greater(*root->objects[index],v, attrPos)){
return root->objects[index];
} else {
assert(index>0);
return root->objects[index-1];
}
}
}
return cand;
}
};
} // end namespace
#endif