/**
* A template BTree
*
* Author: Erel Segal
* Date: 2010-10-14
*/
#include <string>
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
template <typename K, typename T, int MIN_RANK> class BTree {
vector< pair<K,T> > pairs;
vector<BTree<K,T,MIN_RANK>*> children;
BTree<K,T,MIN_RANK>* parent;
// all keys at children[i] are smaller than pairs[i].first
public:
size_t keyCount() const { return pairs.size(); }
size_t childCount() const { return children.size(); }
bool isLeaf() const { return !children[0]; }
static const size_t MAX_KEY_COUNT = 2*MIN_RANK-1;
static const size_t MAX_RANK = 2*MIN_RANK;
BTree<K,T,MIN_RANK>(
int newKeyCount=0, BTree<K,T,MIN_RANK>* newParent=NULL):
pairs(newKeyCount), children(newKeyCount+1), parent(newParent) { }
protected:
size_t indexOfLeastUpperBound(K key) const {
// NOTE: Could use binary search.
for (size_t i=0; i<pairs.size(); ++i) {
if (pairs[i].first >= key)
return i;
}
return pairs.size();
}
// If there are too many children, split them in the middle
void splitChildrenIfNeeded() {
if (pairs.size() > MAX_KEY_COUNT) {
size_t MEDIAN_KEY_INDEX = (int) ((pairs.size()-1)/2);
pair<K,T>& pair_to_promote = pairs[MEDIAN_KEY_INDEX];
cout << "splitting at " << pair_to_promote.first << endl;
// child 0 includes all keys less than k:
BTree<K,T,MIN_RANK>* leftChild = new BTree<K,T,MIN_RANK> (MEDIAN_KEY_INDEX, this);
leftChild->pairs.assign(pairs.begin(), pairs.begin()+MEDIAN_KEY_INDEX);
leftChild->children.assign(children.begin(), children.begin()+MEDIAN_KEY_INDEX+1);
// child 1 includes all keys greater than k:
BTree<K,T,MIN_RANK>* rightChild = new BTree<K,T,MIN_RANK> (pairs.size()-MEDIAN_KEY_INDEX-1, this);
rightChild->pairs.assign(pairs.begin()+MEDIAN_KEY_INDEX+1, pairs.end());
rightChild->children.assign(children.begin()+MEDIAN_KEY_INDEX+1, children.end());
if (parent) { // b2a. split a non-root leaf
int iParentLUB = parent->indexOfLeastUpperBound(pair_to_promote.first);
cout << "moving to parent as #" << iParentLUB << endl;
parent->pairs.insert(parent->pairs.begin()+iParentLUB, pair_to_promote);
parent->children.insert(parent->children.begin()+iParentLUB, leftChild);
parent->children[iParentLUB+1] = rightChild;
parent->splitChildrenIfNeeded();
leftChild->parent = rightChild->parent = parent;
} else { // b2b. we are at the root - create a new root with a single key
cout << "creating a new root" << endl;
//pairs.clear();
//pairs.push_back(pair_to_promote);
pairs[0] = pair_to_promote;
pairs.erase(pairs.begin()+1, pairs.end());
//pairs.push_back(pair_to_promote);
printKeys(cout);
children.clear();
children.push_back(leftChild);
children.push_back(rightChild);
leftChild->parent = rightChild->parent = this;
}
}
}
public:
// return a pointer to the data related to the given key, or NULL if not found.
T* get (K key) {
size_t iLUB = indexOfLeastUpperBound(key);
if (iLUB<pairs.size()) {
pair<K,T>& keyValue = pairs[iLUB];
if (key==keyValue.first)
return &keyValue.second;
}
return (children[iLUB]? children[iLUB]->get(key): NULL);
}
void insert(K key, T value) {
size_t iLUB = indexOfLeastUpperBound(key);
if (iLUB<pairs.size()) {
pair<K,T>& keyValue = pairs[iLUB];
if (key==keyValue.first) {
keyValue.second = value;
return;
}
}
//printKeys(cout);
cout << "inserting " << key << " as #" << iLUB << endl;
if (children[iLUB]) { // a. insert it at the child, or -
children[iLUB]->insert(key,value);
return;
} else { // b. add it to this leaf
pairs.insert (pairs.begin()+iLUB, pair<K,T>(key,value));
children.insert (children.begin()+iLUB, NULL); // insert an empty child (it's a leaf)
splitChildrenIfNeeded();
return;
}
}
void printInOrder(ostream& out, string prefix="") const {
if (!pairs.size())
return;
const pair<K,T>* pair0 = &pairs[0];
if (children[0]) {
out << prefix+" BEFORE " << pair0->first << ":" << endl;
children[0]->printInOrder(out, prefix+" ");
}
out << prefix << pair0->first << ": " << pair0->second << endl;
size_t lastChild = children.size()-1;
for (size_t i=1; i<lastChild; ++i) {
const pair<K,T>* before = &pairs[i-1];
const pair<K,T>* after = &pairs[i];
if (children[i]) {
out << prefix+" BETWEEN " << before->first << " AND " << after->first << ":" << endl;
children[i]->printInOrder(out, prefix+" ");
}
out << prefix << after->first << ": " << after->second << endl;
}
if (children[lastChild]) {
const pair<K,T>* pairLast = &pairs[lastChild-1];
out << prefix+" AFTER " << pairLast->first << ":" << endl;
children[lastChild]->printInOrder(out, prefix+" ");
}
}
// for debug:
void printKeys(ostream& out) const {
out << pairs.size() << " keys:";
for (size_t i=0; i<pairs.size(); ++i) {
out << pairs[i].first << " ";
}
out << endl;
}
}; // template class BTree
int main() {
BTree<string, int, 2> atree;
atree.printInOrder(cout); cout<<endl;
atree.insert ("b",1);
atree.printInOrder(cout); cout<<endl;
atree.insert ("c",8);
atree.printInOrder(cout); cout<<endl;
atree.insert ("g",7);
atree.printInOrder(cout); cout<<endl;
atree.insert ("h",3);
atree.printInOrder(cout); cout<<endl;
atree.insert ("k",6);
atree.printInOrder(cout); cout<<endl;
atree.insert ("d",2);
atree.printInOrder(cout); cout<<endl;
atree.insert ("m",4);
atree.printInOrder(cout); cout<<endl;
atree.insert ("r",5);
atree.printInOrder(cout); cout<<endl;
atree.insert ("w",5);
atree.printInOrder(cout); cout<<endl;
atree.insert ("z",5);
atree.printInOrder(cout); cout<<endl;
atree.insert ("a",9);
atree.printInOrder(cout); cout<<endl;
cout << "a = " << *atree.get ("a") << endl;
cout << "b = " << *atree.get ("b") << endl;
cout << "c = " << *atree.get ("c") << endl;
cout << "d = " << *atree.get ("d") << endl;
cout << "g = " << *atree.get ("g") << endl;
cout << "h = " << *atree.get ("h") << endl;
cout << "k = " << *atree.get ("k") << endl;
cout << "m = " << *atree.get ("m") << endl;
cout << "r = " << *atree.get ("r") << endl;
cout << "w = " << *atree.get ("w") << endl;
cout << "z = " << *atree.get ("z") << endl;
}