/**** BpmDj: Free Dj Tools Copyright (C) 1995-2007 Werner Van Belle This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ****/ #include <stdlib.h> #include <stdio.h> #include <assert.h> #include "avltree.h" #define LEFT_NODE(watte) (watte->left) #define RIGHT_NODE(watte) (watte->right) #define SET_LEFT_NODE(watte,to) (watte->left=to) #define SET_RIGHT_NODE(watte,to) (watte->right=to) #define POSITIVE_FLAG(watte) (watte->flag == 1) #define NEGATIVE_FLAG(watte) (watte->flag == -1) #define ZERO_FLAG(watte) (watte->flag == 0) #define SET_ZERO_FLAG(watte) (watte->flag = 0) #define SET_POSITIVE_FLAG(watte) (watte->flag = 1) #define SET_NEGATIVE_FLAG(watte) (watte->flag = -1) #define NULL_NODE Node<Key>::Null template <class Key> Sentinel<Key> * Node<Key>::Null = new Sentinel<Key>(); //--------------------------------------------------------- // The Sentinel //--------------------------------------------------------- template <class Key> class Sentinel: public Node<Key> { public: virtual int compareAddData(Node<Key>*) {assert(0); return 0;}; virtual int compareSearchData(Key) {assert(0); return 0;}; virtual void print() {assert(0); return;}; virtual void print(int) { return; }; virtual int depth() { return 0; }; virtual int count() { return 0; }; virtual bool isNull() { return true; }; virtual bool valid() { return true; }; virtual Node<Key>* search(Key) { return this; }; virtual Node<Key>* RotateLeft(int&) {assert(0); return 0;}; virtual Node<Key>* RotateRight(int&) {assert(0); return 0;}; virtual Node<Key>* LeftFreedom(Node<Key>* &, int&) {assert(0); return 0;}; virtual Node<Key>* RightFreedom(Node<Key>* &, int&) {assert(0); return 0;}; virtual Node<Key>* GetLeftFreedom(Node<Key>* &, int&) {assert(0); return 0;}; virtual Node<Key>* GetRightFreedom(Node<Key>* &, int&) {assert(0); return 0;}; virtual Node<Key>* DeleteAvlNode(Key, int&) { return this; }; virtual Node<Key>* AddAvlNode(Node<Key>* who, int& depthchanged) { depthchanged=1; return who; }; }; //--------------------------------------------------------- // Count calculation //--------------------------------------------------------- template <class Key> int Node<Key>::count() { return 1 + left->count() + right->count(); } //--------------------------------------------------------- // Depth calculation //--------------------------------------------------------- template <class Key> int Node<Key>::depth() { int l = left->depth(); int r = right->depth(); if (l>r) return l + 1; return r + 1; } //--------------------------------------------------------- // Printing //--------------------------------------------------------- template <class Key> void Node<Key>::print(int prefix) { right->print(prefix + 1); for( int t = prefix; t > 0; t--) printf("."); print(); int l = left->depth(); int r = right->depth(); printf(" left=%d, right=%d, count=%d ",l,r,count()); // SANITY CHECK !!! if ( abs(l-r)>1 || (l < r && ! flag > 0 ) || (l > r && ! flag < 0 ) || (l == r && ! flag == 0 ) ) printf("*********"); printf("\n"); left->print(prefix + 1); } //--------------------------------------------------------- // Consistency validation //--------------------------------------------------------- template <class Key> bool Node<Key>::valid() { if (!left->valid()) return false; if (!right->valid()) return false; if (POSITIVE_FLAG(this)) return left->depth() == right->depth() - 1 ; if (NEGATIVE_FLAG(this)) return left->depth() == right->depth() + 1 ; return left->depth() == right->depth(); } //--------------------------------------------------------- // Search //--------------------------------------------------------- template <class Key> Node<Key>* Node<Key>::search(Key watte) { int compareResult = compareSearchData(watte); if (compareResult == 0 ) return this; if (compareResult == 1 ) return left->search(watte); if (compareResult == -1) return right->search(watte); return NULL_NODE; } //--------------------------------------------------------- // Add //--------------------------------------------------------- #define LEFT(WHO) WHO(Left,Right,LEFT_NODE,RIGHT_NODE,SET_LEFT_NODE,SET_RIGHT_NODE,\ NEGATIVE_FLAG,POSITIVE_FLAG,SET_NEGATIVE_FLAG,SET_POSITIVE_FLAG) #define RIGHT(WHO) WHO(Right,Left,RIGHT_NODE,LEFT_NODE,SET_RIGHT_NODE,SET_LEFT_NODE,\ POSITIVE_FLAG,NEGATIVE_FLAG,SET_POSITIVE_FLAG,SET_NEGATIVE_FLAG) #define CREATE_ROTATE(lname,rname,LN,RN,SLN,SRN,NF,PF,SNF,SPF)\ template <class Key> Node<Key>* Node<Key>::Rotate##lname(int& depthchanged)\ {\ Node<Key>* sec;\ sec=RN(this);\ assert(PF(this));\ if (!(NF(sec)))\ {\ SRN(this,LN(sec));\ SLN(sec,this);\ if (PF(sec))\ {\ SET_ZERO_FLAG(this);\ SET_ZERO_FLAG(sec);\ depthchanged=1;\ return sec;\ }\ SPF(this);\ SNF(sec);\ return sec;\ }\ {\ Node<Key>* third=LN(sec);\ SLN(sec,RN(third));\ SRN(this,LN(third));\ SRN(third,sec);\ SLN(third,this);\ depthchanged=1;\ if (NF(third))\ {\ SPF(sec);\ SET_ZERO_FLAG(this);\ SET_ZERO_FLAG(third);\ return third;\ }\ if (ZERO_FLAG(third))\ {\ SET_ZERO_FLAG(sec);\ SET_ZERO_FLAG(third);\ SET_ZERO_FLAG(this);\ return third;\ }\ SET_ZERO_FLAG(sec);\ SNF(this);\ SET_ZERO_FLAG(third);\ return third;\ }\ } LEFT(CREATE_ROTATE); RIGHT(CREATE_ROTATE); #define CREATE_HANG(lname,rname,LN,RN,SLN,SRN,NF,PF,SNF,SPF) {\ SLN(this,LN(this)->AddAvlNode(who,heightchanged));\ if (heightchanged) {\ if (ZERO_FLAG(this)) {\ SNF(this);\ depthchanged=1;\ return this; }\ if (PF(this)) {\ SET_ZERO_FLAG(this);\ return this; }\ heightchanged=0;\ Node<Key> *tmp = Rotate##rname(heightchanged);\ if (!heightchanged) depthchanged=1;\ return tmp; }\ return this; } template <class Key> Node<Key>* Node<Key>::AddAvlNode(Node<Key>* who, int& depthchanged) { int heightchanged=0; int CompareResult=compareAddData(who); assert(CompareResult); // this means 'no duplicates' if (CompareResult > 0) LEFT(CREATE_HANG); RIGHT(CREATE_HANG); } //--------------------------------------------------------- // Deletion //--------------------------------------------------------- #define CREATE_FREEDOM(lname,rname,LN,RN,SLN,SRN,NF,PF,SNF,SPF)\ template <class Key> Node<Key>* Node<Key>::lname##Freedom (Node<Key>* &placetostorefreedom,int &heightchanged) {\ if (RN(this)->isNull()) \ {\ if ((LN(this))->isNull()) {\ placetostorefreedom=this;\ heightchanged=1;\ return NULL_NODE; }\ heightchanged=1;\ placetostorefreedom=this;\ return LN(this); \ }\ {\ int takverkleind=0;\ SRN(this, RN(this) -> lname##Freedom (placetostorefreedom,takverkleind));\ if (takverkleind) \ {\ if (NF(this)) return Rotate##rname (heightchanged);\ if (PF(this))\ {\ SET_ZERO_FLAG(this);\ heightchanged=1;\ return this;\ }\ SNF(this);\ return this;\ }\ return this;\ }\ }\ \ template <class Key> Node<Key>* Node<Key>::Get##lname##Freedom(Node<Key>* &placetostorefreedom,int &heightchanged)\ {\ Node<Key>* lname;\ assert(LN(this));\ lname = LN(this);\ if (RN( lname ))\ return lname -> lname##Freedom (placetostorefreedom, heightchanged);\ heightchanged=1;\ placetostorefreedom= lname;\ return LN( lname );\ } LEFT(CREATE_FREEDOM) RIGHT(CREATE_FREEDOM) #define CREATE_ZAK(lname,rname,LN,RN,SLN,SRN,NF,PF,SNF,SPF)\ SLN(this,LN(this)->DeleteAvlNode(wie,takkleiner));\ if (takkleiner) {\ if (NF(this)) {\ SET_ZERO_FLAG(this);\ heightchanged=1;\ return this; }\ if (ZERO_FLAG(this)) {\ SPF(this);\ return this; }\ return Rotate##lname (heightchanged); }\ return this; template <class Key> Node<Key>* Node<Key>::DeleteAvlNode(Key wie, int& heightchanged) { int CompareResult,takkleiner=0; CompareResult=this->compareSearchData(wie); switch (CompareResult) { case -1: /* this<wie */ RIGHT(CREATE_ZAK); case 1: /* this>wie */ LEFT(CREATE_ZAK); case 0: /* this==wie */ /* nu een opnderscheid maken voor welke kinderen de * this heeft */ if (LEFT_NODE(this)->isNull() && RIGHT_NODE(this)->isNull()) { heightchanged=1; delete this; // WVB !! Dangerours ??? return NULL_NODE; } if (LEFT_NODE(this)->isNull()) { Node<Key>* rechter; rechter=RIGHT_NODE(this); assert(POSITIVE_FLAG(this)); assert(rechter); assert(LEFT_NODE(rechter)->isNull()); assert(RIGHT_NODE(rechter)->isNull()); heightchanged=1; delete this; // WVB -- dangerous return rechter; } if (RIGHT_NODE(this)->isNull()) { Node<Key>* linker; linker=LEFT_NODE(this); assert(NEGATIVE_FLAG(this)); assert(linker); assert(LEFT_NODE(linker)->isNull()); assert(RIGHT_NODE(linker)->isNull()); heightchanged=1; delete this; // WVB -- dangerours ??? return linker; } if (POSITIVE_FLAG(this)) { Node<Key>* freedom; SET_RIGHT_NODE(this,GetRightFreedom(freedom,heightchanged)); SET_LEFT_NODE(freedom,LEFT_NODE(this)); SET_RIGHT_NODE(freedom,RIGHT_NODE(this)); if (heightchanged) SET_ZERO_FLAG(freedom); else SET_POSITIVE_FLAG(freedom); delete this; // WVB -- dangerous ??? return freedom; } if (NEGATIVE_FLAG(this)) { Node<Key>* freedom; SET_LEFT_NODE(this,GetLeftFreedom(freedom,heightchanged)); SET_LEFT_NODE(freedom,LEFT_NODE(this)); SET_RIGHT_NODE(freedom,RIGHT_NODE(this)); if (heightchanged) SET_ZERO_FLAG(freedom); else SET_NEGATIVE_FLAG(freedom); delete this; // WVB -- dangerours ?? return freedom; } if (ZERO_FLAG(this)) { Node<Key>* freedom; int takverkleind=0; SET_LEFT_NODE(this,GetLeftFreedom(freedom,takverkleind)); SET_LEFT_NODE(freedom,LEFT_NODE(this)); SET_RIGHT_NODE(freedom,RIGHT_NODE(this)); if (takverkleind) SET_POSITIVE_FLAG(freedom); else SET_ZERO_FLAG(freedom); delete this; // WVB -- dangerours return freedom; } default: exit(57); } } //--------------------------------------------------------- // Constructor and Wrappers //--------------------------------------------------------- template <class Key> Node<Key>::Node() { left = NULL; right = NULL; } template <class Key> AvlTree<Key>::AvlTree() { init(); }; template <class Key> void AvlTree<Key>::init() { root = Node<Key>::Null; }; template <class Key> void AvlTree<Key>::PurgeAll(Node<Key>* root) { if (root && !root->isNull()) { PurgeAll(root->left); PurgeAll(root->right); delete(root); } } template <class Key> AvlTree<Key>::~AvlTree() { purge(); }; template <class Key> Node<Key>* AvlTree<Key>::AddAvlNode(Node<Key>* root, Node<Key>* who) { if (who->isNull()) return root; who->left = NULL_NODE; who->right = NULL_NODE; who->flag = 0; int depthchanged=0; return root->AddAvlNode(who,depthchanged); } template <class Key> Node<Key>* AvlTree<Key>::DeleteAvlNode(Node<Key>* root, Key wie) { int heightchanged=0; return root->DeleteAvlNode(wie,heightchanged); }