/*----------------------------------------------------------------*\ CS130 Assignment #2 OOP23.CPP - Implementation of 2-3-TREE | | An Object Oriented Approach to Implementation Of 2-3-TREE | \*----------------------------------------------------------------*/ /*----------------------------------------------------------------*\ | CLASSES USED | ------------------ | Instance Classes : Data (For storing relevant info about each entry) Node Tree_23 Static function Classes : Interface ( Interface handling functions ) \*----------------------------------------------------------------*/ #include #include #include #include enum {LEFT,MIDDLE,RIGHT}; enum {ADDING,SPLITTING}; enum {SEARCH,DISPLAY}; const int MAXTREES=20; const int MAXWORDLENGTH=80; //___________Interface class to handle the interface____________ class Interface { public: static void Clear(); static void DisplayCenter(char *s); static void DisplayLine(char *s); static void PressEnter(); static void Leavespace(int i); static int GetInt(char* message,int ll); static long GetLong(char* message,long ll); static void GetString(char* buffer,char* message); static void Error(char* s) { cout << endl << "Error : " << s << endl; } }; void Interface::Clear() { for(int i=0;i<25;i++) cout << endl; } void Interface::DisplayCenter(char *s) { int i=strlen(s); Leavespace((80-i)/2); cout << s; } void Interface::DisplayLine(char *s) { for (int i=0;i<(80/strlen(s));i++) cout << s; } void Interface::PressEnter() { cout << endl << endl << "Press Enter to continue...."; getchar(); } void Interface::Leavespace(int i) { for(int j=0;j class Node { private: T leftkey,rightkey; Data* data; //___________3 children pointers____________ Node* children[3]; Node* parent; T lowest; public: //____________Constructor____________ Node(T lk,T rk,Data* d,Node* lc,Node* mc,Node* rc,Node* p,T l) { leftkey=lk; rightkey=rk; if(d==NULL) data=d; else { data=new Data; *data=*d; // Call Assignment operator } children[LEFT]=lc; children[MIDDLE]=mc; children[RIGHT]=rc; parent=p; lowest=l; } //_____________Deconstructor________________ ~Node() { if(data!=NULL) { delete data; data=NULL; } } //_________________INTERFACE FUNCTIONS__________________ //_______Returns the new root after addition___NULL if no change_____ Node* AddElement(T lk,T rk,Data* d,Node* lc,Node* mc,Node* rc,Node* p,T l,int mode=ADDING); Node* DeleteElement(T lk); int SearchElement(T k,int mode=SEARCH); void Display(); //_____________IMPLEMENTATION FUNCTIONS__________________ void Info() { cout << endl <Set_parent(this); if(children[MIDDLE]!=NULL) children[MIDDLE]->Set_parent(this); if(children[RIGHT]!=NULL) children[RIGHT]->Set_parent(this); } //_______Adjust leftkey , rightkey , lowest params_____ //_______according to children_____ void Set_myparameters() { leftkey=children[MIDDLE]->lowest; if(children[RIGHT]!=NULL) rightkey=children[RIGHT]->lowest; else rightkey=0; lowest=children[LEFT]->lowest; } //_______Rearranges children in ascending order_____ //______ir-respective of placement of children_____ //_____( including intervening NULLS)_______ void Rearrange() { Node* temp[3]; int j=0,i; for(i=0;i<=2;i++) { if(children[i]!=NULL) { temp[j]=children[i]; j++; } } SortLeafs(temp,j); for(i=0;i Node* Node::AddElement(T lk,T rk,Data* d,Node* lc,Node* mc,Node* rc,Node* p,T l,int mode) { //__________Check special Cases if I am root________ if (parent==NULL && mode==ADDING) // _____Unique property of root { if(children[LEFT]==NULL) //___Left child is NULL___0 children yet { children[LEFT]=new Node(lk,0,d,NULL,NULL,NULL,this,lk); leftkey=children[LEFT]->Return_lowest()+1; lowest=children[LEFT]->Return_lowest(); return NULL; } else if(children[MIDDLE]==NULL) { Node* temp=new Node(lk,0,d,NULL,NULL,NULL,this,lk); Node* array[2]={children[LEFT],temp}; SortLeafs(array,2); //____Redistribute___ children[LEFT]=array[0]; children[MIDDLE]=array[1]; leftkey=children[MIDDLE]->Return_lowest(); rightkey=0; lowest=children[LEFT]->Return_lowest(); return NULL; } } //___________REGULAR ADDITION STATS HERE____________ //_________See if in ADDING mode and not SPLITTING_____________ if(children[LEFT]->IsLeaf()==0 && mode==ADDING) // If lower node is not a leaf { // then simply call other objects if(lkAddElement(lk,0,d,NULL,NULL,NULL,this,lk); } else if( (rightkey==0 && lk>=leftkey) || (lk=leftkey) ) { return children[MIDDLE]->AddElement(lk,0,d,NULL,NULL,NULL,this,lk); } else if( lk>=rightkey) { return children[RIGHT]->AddElement(lk,0,d,NULL,NULL,NULL,this,lk); } } //__________Lower Child is a leaf____Actual adding part has come !_____ else { Node* temp; temp=new Node(lk,rk,d,lc,mc,rc,p,l); temp->Set_mychildren(); if(children[RIGHT]==NULL) //_______Only two leafs , insertion easy !_____ { children[RIGHT]=temp; SortLeafs(children,3); //__________Redistribute keys and lowest fields____________ leftkey=children[MIDDLE]->Return_lowest(); rightkey=children[RIGHT]->Return_lowest(); lowest=children[LEFT]->Return_lowest(); Set_mychildren(); return NULL; } // _________3 Children__Tough part , split upper parent into two_________ else { Node* array[4]={children[LEFT],children[MIDDLE], children[RIGHT],temp}; Node* temp1; Node* temp2; SortLeafs(array,4); children[LEFT]=array[0]; children[MIDDLE]=array[1]; children[RIGHT]=NULL; temp1=array[2]; temp2=array[3]; //__________Redistribute keys and lowest fields____________ leftkey=children[MIDDLE]->Return_lowest(); rightkey=0; lowest=children[LEFT]->Return_lowest(); Set_mychildren(); if(parent!=NULL) //_____ if i am not root { return parent->AddElement(temp2->Return_lowest(), 0,NULL,temp1,temp2,NULL,parent,temp1->Return_lowest(),SPLITTING); } // _______I am the root___splitting myself and creating a new root_____ else { Node* temp3; Node* root; //________My sibling under the new root_____ temp3=new Node(temp2->Return_lowest(),0,NULL,temp1,temp2,NULL, NULL,temp1->Return_lowest()); //____________The new root___________ root=new Node(temp3->Return_lowest(),0,NULL,this,temp3,NULL,NULL, lowest); //_______New Root is made so set new parents____ temp3->Set_mychildren(); root->Set_mychildren(); return root; } } } return NULL; // ____Appease c++ } template void Node::SortLeafs(Node** nodearray,int n) { int i,j; //__________Simple Bubble sort Procedure for sorting leafs________ for(i=0;iReturn_lowest() > nodearray[j]->Return_lowest()) SwapPointers(nodearray[i],nodearray[j]); } template void Node::SwapPointers(Node* &p1,Node* &p2) { Node* temp; temp=p1; p1=p2; p2=temp; } template Node* Node::DeleteElement(T lk) { //______Check for special Cases if one or two elements left_____ int child_id; if(children[LEFT]->IsLeaf()==0) { //________assign child_id the appropriate child to call______ if(lk=leftkey) || (lk=leftkey) ) child_id=MIDDLE; else if( lk>=rightkey) child_id=RIGHT; children[child_id]->DeleteElement(lk); //________Only One children left_____________ if(children[child_id]->Return_childrenno()==1) { Node* t=NULL; //______look for three children sibling in adjacent nodes______ int left_status=0; //_____try left sibling_____ int i=child_id-1; if(i>=0) // if left sibling is valid; { //______A adjacent node with 3 children found !______ if(children[i]->Return_childrenno()==3) { t=children[i]->children[RIGHT]; children[i]->children[RIGHT]=NULL; children[i]->Set_myparameters(); left_status=1; // ____Success on left adjacent node } } if(left_status==0) { //________try right sibling_________ i=child_id+1; if(i<=2 && children[i]!=NULL) // if right sibling is valid; { //______A adjacent right node with 3 children found !______ if(children[i]->Return_childrenno()==3) { t=children[i]->children[LEFT]; children[i]->children[LEFT]=NULL; children[i]->Rearrange(); children[i]->Set_myparameters(); } } } // ___________If extra child found______________ if(t!=NULL) { children[child_id]->children[MIDDLE]=t; children[child_id]->Rearrange(); children[child_id]->Set_mychildren(); children[child_id]->Set_myparameters(); } //____________Failure no, no extra child found___ //________Transfer one child to sibling_____ else { t=children[child_id]->children[LEFT]; //________delete its parent________ delete children[child_id]; children[child_id]=NULL; i=child_id-1; if(i<0) i=child_id+1; //__________Insert it anywhere children[i]->children[RIGHT]=t; children[i]->Rearrange(); children[i]->Set_mychildren(); children[i]->Set_myparameters(); } } Rearrange(); Set_mychildren(); if(Return_childrenno()!=1) { Set_myparameters(); } //____________Check Special Case__________ if(parent==NULL && Return_childrenno()==1) { children[LEFT]->Set_parent(NULL); return children[LEFT]; } } //_____________Reached the leaf , finally delete the required element_______ else { for(int i=0;i<=2;i++) { if(children[i]!=NULL && children[i]->leftkey==lk) { delete children[i]; children[i]=NULL; } } Rearrange(); if(Return_childrenno()>1) Set_myparameters(); } return NULL; } template void Node::Display() { //cout << "\nPresent Node -> " << leftkey << " " << rightkey << " " << lowest << " p : " << parent << " me : " << this; if(IsLeaf()) //____2nd condition -> i am not root______ { cout << endl << leftkey ; } else { if(children[LEFT]!=NULL) children[LEFT]->Display(); if( children[MIDDLE]!=NULL) children[MIDDLE]->Display(); if( children[RIGHT]!=NULL) children[RIGHT]->Display(); } } template int Node::SearchElement(T k,int mode) { if(IsLeaf()) //____2nd condition -> i am not root______ { if(k==leftkey) { if(mode==DISPLAY) if(data!=NULL) data->Display(); return 1; } else return 0; } else { int a=0; if(children[LEFT]!=NULL) a=a | children[LEFT]->SearchElement(k,mode); if( children[MIDDLE]!=NULL) a=a | children[MIDDLE]->SearchElement(k,mode); if( children[RIGHT]!=NULL) a= a | children[RIGHT]->SearchElement(k,mode); return a; } } //------------------------------------------ // T R E E _ 2 3 C L A S S //________________________________________ template class Tree_23 { private: Node* root; // ___Store the root pointer____ int no_of_elements; public: //_____Constructors , Destructors______ Tree_23(); ~Tree_23() { // ________Add Memory De-allocation routines for complete Tree delete root; root=NULL; } void AddElement(T key,Data& d); int SearchElement(T key,int mode=SEARCH); void DeleteElement(T key); void Display(); int Return_no_of_elements() { return no_of_elements; } }; template Tree_23::Tree_23() { root=new Node(0,0,NULL,NULL,NULL,NULL,NULL,0); no_of_elements=0; } template void Tree_23::AddElement(T key,Data& d) { Node* temp=root->AddElement(key,0,&d,NULL,NULL,NULL,NULL,key); if(temp!=NULL) { root=temp; } no_of_elements++; } template void Tree_23::DeleteElement(T key) { Node* t; t=root->DeleteElement(key); if(t!=NULL) { delete root; root=t; } no_of_elements--; } template void Tree_23::Display() { root->Display(); } template int Tree_23::SearchElement(T key,int mode) { return root->SearchElement(key,mode); } /*--------------------------------------------------------*\ | M A I N C O N S O L E | \*--------------------------------------------------------*/ //__________________________Main user console starts____________________ void main() { Tree_23 tree[MAXTREES]; long key; int currenttree=0; int choice; Data data; while(1) { Interface::Clear(); //________Display Main Menu_______ Interface::DisplayCenter("2-3-TREE Demonstration Program"); cout << endl; Interface::DisplayLine("-"); cout << endl << endl; Interface::DisplayCenter("-----> MAIN MENU <------"); cout << endl << endl; Interface::Leavespace(25); cout << "1. Add a name to TREE"; cout << endl; Interface::Leavespace(25); cout << "2. Search for a name"; cout << endl; Interface::Leavespace(25); cout << "3. Delete a name"; cout << endl; Interface::Leavespace(25); cout << "4. Display all entries in TREE"; cout << endl; Interface::Leavespace(25); cout << "5. Change current TREE"; cout << endl; Interface::Leavespace(25); cout << "6. Exit the Program"; cout << endl; cout << endl; Interface::DisplayLine("_"); cout << endl; cout << "Current TREE number is : " << (currenttree+1) << endl; cout << "No. of entries in current TREE is : " << tree[currenttree].Return_no_of_elements() << endl; cout << "Maximum number of TREES allowed : " << MAXTREES << endl << endl; choice=Interface::GetInt("Please Enter your choice :",1); switch (choice) { case 1: cout << endl; cout << endl << "Help : When you want to stop , just enter 0 as the last number" << endl; key=1; while(key!=0) { key=Interface::GetLong("\nPlease Enter the Entry No. :",0); if (tree[currenttree].SearchElement(key)) { cout << endl; cout << key << " is already present in the TREE"; } else if(key>0) { data.GetData(); tree[currenttree].AddElement(key,data); } } break; case 2: key=Interface::GetLong("\nPlease Enter the number to search: ",1); if (tree[currenttree].SearchElement(key,SEARCH)) { cout << endl; cout << key << " is present in the TREE"; tree[currenttree].SearchElement(key,DISPLAY); } else { cout << endl; cout << key << " is not present in the TREE"; } Interface::PressEnter(); break; case 3: key=Interface::GetLong("\nPlease Enter the number to delete :",1); if (!tree[currenttree].SearchElement(key,SEARCH)) { cout << endl; cout << key << " is not present in the TREE"; Interface::PressEnter(); break; } tree[currenttree].DeleteElement(key); break; case 4: cout << endl; Interface::DisplayCenter("THE TREE LIST"); cout << endl; Interface::DisplayLine("-"); cout << endl; if(tree[currenttree].Return_no_of_elements()==0) { cout << "\n\nThere are no entries currenly stored in the TREE\n"; } tree[currenttree].Display(); Interface::PressEnter(); break; case 6: cout << endl << endl; Interface::DisplayCenter("Exiting the Program...."); cout << endl; Interface::DisplayLine("-"); cout << endl << endl; exit(0); case 5: int num; cout << endl; cout << "Maximum number allowed is : " << MAXTREES << endl; num=Interface::GetInt("Please Enter the new TREE number :",1); if ( num>=1 && num<=MAXTREES) { currenttree=num-1; } else { Interface::Error("Number entered is not valid."); Interface::PressEnter(); } break; default: Interface::Error("Wrong Choice !!"); Interface::PressEnter(); } } }