/* Author : Rick van der Zwet * S-number : 0433373 * Version : $Id: trie.cc 330 2007-11-25 23:31:30Z rick $ * Copyright : FreeBSD Licence */ #include "trie.h" #include #include #ifndef TRIE_CC #define TRIE_CC template TrieNode::TrieNode() { Value = '\0'; One = NULL; Zero = NULL; Parent = NULL; } template TrieNode::~TrieNode() { delete One; delete Zero; } template Trie::Trie () { Root = new TrieNode (); //Set window to root GoRoot (); } template Trie::~Trie () { delete Root; } template bool Trie::AtLeaf () { if (Window->One == NULL and Window->Zero == NULL) { return(true); } // Got some extra nodes down below return(false); } template void Trie::GoChild (char K) { // Call ExistsChild to check if node exists and deliver an pointer // to the node in NodeFound if ( ExistsChild(K) ) { Window = NodeFound; } } template void Trie::GoRoot () { //set the current window on the Root pointer Window = Root; } template bool Trie::ExistsChild (char K) { // worker with different knob, to make it able to get back TrieNode * Worker = Window; int i; for (i = 7; i >= 0; i--) { // bit i is 1 or not? if (K & 1<One == NULL) { return false; } else { Worker = Worker->One; } } else { // If node not exists, bail out if (Worker->Zero == NULL) { return false; } else { Worker = Worker->Zero; } } } // Store found window in NodeFound NodeFound = Worker; return true; } template char Trie::FirstChild () { // worker with different knob, to make it able to get back TrieNode * Worker = Window; // walk 8 bits, i indication of the bit currently are int i; // return value char retval = 0; for (i = 7; i >= 0; i--) { // go as many Zero if possible else go right if possible else return \0 if (Worker->Zero != NULL) { Worker = Worker->Zero; } else if (Worker->One != NULL) { //set bit i to 1 retval |= 1<One; } else { retval = '\0'; break; } } return(retval); } /* This does not seems be very logical in the first place, but try to * draw a picture and then follow the paths, just remind 2 things * -no One 'turns' are allowed, cause those are higher order childs * -the story ends if you hit the startnode from the right * XXX: Only works well with one level depth, not multilevel depth */ template char Trie::NextChild (char K) { // store startnode TrieNode * Worker; // tmp (loop) counter int i; // return value, not changed if not found int retval = '\0'; // goto child node if it exists at least if (ExistsChild(K)) { Worker = NodeFound; // depth counter i = 0; while ( true ) { // ends if in startnode and came from right or // in startnode en no left turn possible if (Worker->Parent == Window) { if (Worker->Parent->One == Worker or Worker->Parent->One == NULL) { return(retval); } } //if from left and right available, go for it if (Worker->Parent->Zero == Worker and Worker->Parent->One != NULL) { Worker = Worker->Parent->One; //walk to child leaf while (i > 0) { //decrement counter, cause we are going inward again i--; // if left available take it, else right if (Worker->Zero != NULL) { Worker = Worker->Zero; } else { Worker = Worker->One; } } //calculate value NextChild retval = 0; for (i = 0; i <= 7; i++) { if (Worker->Parent->One == Worker) { retval |= 1<Parent; } //should never happen if (Worker != Window) { perror("BUG: NextChild find value error"); exit(1); } return(retval); } //set new value Worker Worker = Worker->Parent; //raise counter i++; } // end none found return(retval); } // no valid leaf return(retval); } template void Trie::AddChild (char K) { //get worker pointer TrieNode * Worker = Window; int i; for (i = 7; i >= 0; i--) { //bit i is 1 or not? if (K & 1<One == NULL) { Worker->One = new TrieNode(); } Worker->One->Parent = Worker; Worker = Worker->One; } else { // check is node exists, else create new one if (Worker->Zero == NULL) { Worker->Zero = new TrieNode(); } Worker->Zero->Parent = Worker; Worker = Worker->Zero; } } } template void Trie::RemoveChild (char K) { TrieNode * Worker; int i; //loop counter //check whether this knob exists if ( ExistsChild(K) ) { Worker = NodeFound; //and is leaf if (Worker->One == NULL and Worker->Zero == NULL) { //delete obsolete knob and null refering pointer // walk 7 steps up and delete node if both pointers are zero // first step is special cause the other could be a leaf as // well //goto parent Worker = Worker->Parent; //deleted leaf specified at NodeFound if (Worker->One == NodeFound) { delete Worker->One; Worker->One = NULL; } else { delete Worker->Zero; Worker->Zero = NULL; } for (i = 0; i <= 6; i++) { // go one up Worker = Worker->Parent; //XXX: Only need to check the node we came from, instead //of both // Check wether we could delete arch 1 if (Worker->One != NULL) { //delete subnode if both pointers are NULL if (Worker->One->One == NULL and Worker->One->Zero == NULL) { delete Worker->One; Worker->One = NULL; } } // Check wether we could delete arch 0 if (Worker->Zero != NULL) { //delete subnode if both pointers are NULL if (Worker->Zero->One == NULL and Worker->Zero->Zero == NULL) { delete Worker->Zero; Worker->Zero = NULL; } } } //Should never happen if (Window != Worker) { perror("BUG: Pointer delete error"); exit(1); } } } } template void Trie::PutInfo (InfoTp I) { Window->Value = I; } template InfoTp Trie::GetInfo () { return(Window->Value); } template void Trie::GotoNode(TrieNode *Nd) { Window = Nd; } template TrieNode *Trie::GetNode() { return(Window); } #endif