- /*
- * ExtendedHashing.cpp
- *
- * Copyright 2009 roKB <rooparambhakar@gmail.com>
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
- #include <string>
- #include <cassert>
- #include <iostream>
- #include <cstdio>
- #include <cstdlib>
- int hashCode(std::string const & key)
- /*
- * calculates the hash of key using polynomial expansion,
- * with x = 37
- */
- {
- const long x = 41L;
- int n = key.length();
- long value = 0L;
- while( n-- > 0 ) {
- value *= x; value += key[n];
- }
- return static_cast<int>(value);
- }
- // ------------------------------------------------------------------------
- // ------------------------------------------------------------------------
- struct Student
- {
- std::string entryNo;
- std::string name;
- };
- std::ostream& operator << (std::ostream& out, Student& s) {
- out << s.entryNo << " : " << s.name;
- return out;
- }
- // ------------------------------------------------------------------------
- // ------------------------------------------------------------------------
- struct Node
- /* sentinal nodes of linked list */
- {
- Node *next;
- };
- struct Pair {
- int first;
- Student *second;
- ~Pair() {
- if(second != NULL)
- delete second;
- }
- };
- struct InternalNode : public Node
- /* internal nodes of linked list */
- {
- Pair *element;
- ~InternalNode() {
- delete element;
- }
- };
- class LinkedList
- /*
- * buckets in hash table
- */
- {
- public:
- LinkedList() {
- head = new Node();
- head->next = NULL;
- }
- ~LinkedList() {
- del(head);
- }
- void insert(Student & elem, int hashkey) {
- // create hash, data pair
- Pair *data = new Pair();
- data->first = hashkey;
- data->second = &elem;
- // create node in list
- InternalNode *temp = new InternalNode();
- temp->next = head->next;
- temp->element = data;
- head->next = temp;
- }
- Student* search(int hashkey) {
- Node *current = head->next;
- while(current != NULL) {
- if(static_cast<InternalNode*>(current)->element->first == hashkey)
- return static_cast<InternalNode*>(current)->element->second;
- current = current->next;
- }
- return NULL;
- }
- void remove(int hashkey) {
- Node *current = head->next;
- Node *parent = head;
- while(current != NULL) {
- if(static_cast<InternalNode*>(current)->element->first == hashkey) {
- // fix links in list then remove and return
- parent->next = current->next;
- current->next = NULL;
- del(current);
- return;
- }
- parent = current;
- current = current->next;
- }
- }
- void removeAll() {
- del(head->next);
- head->next = NULL;
- }
- void print(){
- InternalNode *current = static_cast<InternalNode*>(head->next);
- int i = 1;
- while(current != NULL) {
- std::cout << i << " : hashkey(0x" << std::hex << static_cast<unsigned int>( current->element->first ) << ") <" << *(current->element->second) << ">" << std::endl;
- current = static_cast<InternalNode*>(current->next);
- ++i;
- }
- }
- Node *getList() {
- return head->next;
- }
- private:
- void del(Node *node) {
- if(node == NULL)
- return;
- del(node->next);
- delete node;
- }
- Node *head;
- };
- class Bucket
- /*
- * uses LinkedList for storage
- * bucket overflow and underflow is left for xtendedHashing functions
- * they should check for underflow and overflow in bucket, otherwise
- * program will terminate
- */
- {
- public:
- Bucket(int c, int s = 0) : sig_bits(s), cap(c), sz(0), code(0), root(false) {
- data = new LinkedList();
- }
- ~Bucket() {
- delete data;
- }
- int capacity() {
- return cap;
- }
- int size() {
- return sz;
- }
- void insert(Student& elem, int hashkey) {
- data->insert(elem, hashkey);
- ++sz;
- if(root)
- return;
- assert( ( size() <= capacity() ) );
- }
- Student* search(int hashkey) {
- return data->search(hashkey);
- }
- void remove(int hashkey) {
- if(search(hashkey) != NULL)
- --sz;
- data->remove(hashkey);
- assert( (size() >= 0) );
- }
- void emptyBucket() {
- data->removeAll();
- sig_bits = 0;
- sz = 0;
- }
- bool isEmpty() {
- return size() == 0;
- }
- void print() {
- std::cout << "----- <BUCKET (";
- printcode();
- std::cout << ") > -----" << std::endl;
- std::cout << "SIG_BITS : " << sig_bits << std::endl;
- data->print();
- std::cout << std::endl;
- }
- Node* getList() {
- return data->getList();
- }
- int getSIG_BITS() {
- return sig_bits;
- }
- void setSIG_BITS(int s) {
- sig_bits = s;
- assert( (sig_bits >= 0) );
- }
- void setCODE(int c) {
- code = c;
- }
- void setROOT(bool state) {
- root = state;
- }
- private:
- void printcode() {
- int length = sig_bits;
- int temp = code;
- while(length-- > 0) {
- std::cout << temp%2;
- temp >>= 1;
- }
- }
- LinkedList *data;
- int sig_bits;
- int cap;
- int sz;
- int code;
- bool root;
- };
- struct TrieNode
- {
- Bucket *page;
- TrieNode *next[2];
- TrieNode *parent;
- ~TrieNode() {
- if(page != NULL)
- delete page;
- }
- };
- class HashTable
- /*
- * at last we are at the implementation of Extendible-hashTable ^v^
- * uses tries index for bucket lookup
- * "now is the time to show your coding skills rrc"
- */
- {
- public:
- HashTable(int buk = DFL_BUCKET_SIZE) : bucket_size(buk) {
- sig_bits = 0;
- //root = false;
- index = new TrieNode();
- index->page = new Bucket(bucket_size, sig_bits);
- index->next[0] = NULL;
- index->next[1] = NULL;
- index->parent = NULL;
- no_of_buckets = 1;
- }
- ~HashTable() {
- del(index);
- }
- Student* search(std::string number) {
- int code;
- int hashkey = hashCode(number);
- TrieNode *node = findNode(hashkey, &code);
- return node->page->search(hashkey);
- }
- void insert(Student stu) {
- Student & st = *new Student();
- st.name = stu.name;
- st.entryNo = stu.entryNo;
- int hashkey = hashCode(st.entryNo);
- int code;
- TrieNode *node = findNode(hashkey, &code);
- Bucket *page = node->page;
- //if(root || page->size()+1 <= page->capacity())
- if(page->size()+1 <= page->capacity())
- {
- // insert in bucket
- // page->setROOT(root);
- page->insert(st, hashkey);
- // page->setROOT(false);
- return;
- } else { // bucket is full, make a new bucket
- // step 7
- Bucket *newPage = new Bucket(bucket_size);
- no_of_buckets++;
- // step 8
- LinkedList *Q = new LinkedList();
- InternalNode *current = static_cast<InternalNode*>( page->getList() );
- while(current != NULL) {
- Q->insert(*(current->element->second), current->element->first);
- current = static_cast<InternalNode*>(current->next);
- }
- Q->insert(st, hashkey);
- // step 9
- int oldD = page->getSIG_BITS();
- int MASK = 1 << oldD;
- newPage->setSIG_BITS(oldD + 1);
- // step 10
- page->emptyBucket();
- page->setSIG_BITS(oldD + 1);
- if(oldD+1 > sig_bits){
- ++sig_bits;
- }
- node->page = NULL;
- TrieNode *left = new TrieNode();
- TrieNode *right = new TrieNode();
- node->next[0] = left;
- node->next[1] = right;
- left->page = page;
- right->page = newPage;
- left->next[0] = left->next[1] = NULL; left->parent = node;
- right->next[0] = right->next[1] = NULL; right->parent = node;
- left->page->setCODE(code);
- right->page->setCODE(code | MASK);
- current = static_cast<InternalNode*>( Q->getList() );
- // root = true;
- while(current != NULL) {
- insert( *(current->element->second) );
- current = static_cast<InternalNode*>( current->next );
- }
- // root = false;
- }
- }
- void remove(std::string number){
- int hashkey = hashCode(number);
- int code;
- TrieNode *node = findNode(hashkey, &code);
- Bucket *page = node->page;
- if(page->search(hashkey) == NULL)
- return;
- page->remove(hashkey);
- if(page->size() == 0 && node->parent != NULL)
- {
- TrieNode *parent = node->parent;
- TrieNode *sibling = (parent->next[0] == node)?
- (parent->next[1]) : (parent->next[0]);
- if(sibling->next[0] != NULL || sibling->next[1] != NULL)
- return;
- no_of_buckets--;
- parent->page = sibling->page;
- sibling->page = NULL;
- parent->next[0] = NULL;
- parent->next[1] = NULL;
- del(node);
- del(sibling);
- parent->page->setSIG_BITS(parent->page->getSIG_BITS() - 1);
- int MASK = 1 << parent->page->getSIG_BITS();
- MASK -= 1;
- code &= MASK;
- parent->page->setCODE(code);
- sig_bits = max_bits(index);
- }
- }
- void print() {
- std::cout << "-----------------------------------------" << std::endl;
- std::cout << "bucket.capacity : " << bucket_size << "\t|||\t";
- std::cout << "number ( buckets ) : " << no_of_buckets << "\t|||\t";
- std::cout << "max sig_bits : " << sig_bits << std::endl;
- int total = printNode(index);
- std::cout << "-----------------------------------------" << std::endl;
- std::cout << "elements in hashtable : " << total << std::endl;
- std::cout << "-----------------------------------------" << std::endl;
- }
- private:
- TrieNode* findNode(int hashkey, int *const code)
- // using lower sig_bits of hashCode to calculate key
- {
- int d = 1; // mask for calculating key from k
- d <<= sig_bits;
- d -= 1; // all ones
- int key = hashkey & d;
- *code = 0;
- int length = 0;
- TrieNode *current = index;
- while(current != NULL) {
- if(current->page != NULL)
- return current;
- if(current->next[key & 1] != NULL){
- current = current->next[key & 1];
- int MASK = key&1; // current decision
- if(length != 0)
- MASK <<= length;
- *code |= MASK;
- key >>= 1;
- ++length;
- }
- }
- assert( 0 ); // should not come here.
- return NULL;
- }
- void del(TrieNode *node) {
- if(node == NULL)
- return;
- TrieNode *left, *right;
- left = node->next[0];
- right = node->next[1];
- del(left);
- del(right);
- delete node;
- }
- int printNode(TrieNode *current) {
- if(current == NULL)
- return 0;
- if(current->page != NULL) {
- current->page->print();
- return current->page->size();
- }
- int number = printNode(current->next[0]);
- number += printNode(current->next[1]);
- return number;
- }
- int max_bits(TrieNode *node) {
- if(node->page != NULL)
- return node->page->getSIG_BITS();
- int left = max_bits(node->next[0]);
- int right = max_bits(node->next[1]);
- int max = (left > right) ? left : right;
- return max;
- }
- const static int DFL_BUCKET_SIZE = 4; // default bucket size
- TrieNode *index;
- int sig_bits;
- int bucket_size;
- int no_of_buckets;
- //bool root;
- };
- int printMenu() {
- std::system("clear");
- std::cout << "-----------------------------------------" << std::endl;
- std::cout << "Extendible Hashing Implementation." << std::endl;
- std::cout << "-----------------------------------------" << std::endl;
- std::cout << "\t\t 1. Insert a Record" << std::endl;
- std::cout << "\t\t 2. Search a Record" << std::endl;
- std::cout << "\t\t 3. Delete a Record" << std::endl;
- std::cout << "\t\t 4. Show All Records"<< std::endl;
- std::cout << "\t\t 5. Delete All Records" << std::endl;
- std::cout << "\t\t 6. Exit" << std::endl;
- int choice;
- std::cout << "\nChoice : ";
- std::cin >> choice;
- std::cout.flush();
- return choice;
- }
- void credits() {
- std::system("clear");
- std::cout << "\n\n\n";
- std::cout << "\t\t\t ----------------------------------------------" << std::endl;
- std::cout << "\t\t\t /\\--------------------------------------------/\\" << std::endl;
- std::cout << "\t\t\t|| Thanks for evaluating our Extendible Hashing ||" << std::endl;
- std::cout << "\t\t\t|| \t\tImplementation.\t\t\t||" << std::endl;
- std::cout << "\t\t\t \\/--------------------------------------------\\/" << std::endl;
- std::cout << "\t\t\t ----------------------------------------------" << std::endl;
- std::cout << "\n\n\t\tImplementors:-\n";
- std::cout << "\t\t\t2006ECS20\tRooparam Choudhary\t(Main Coder)" << std::endl;
- std::cout << "\t\t\t2006ECS57\tKumar Ranjeet\t\t(Creative Head)" << std::endl;
- std::cout << "\n\nenter to quit...";
- std::getchar();
- }
- int main()
- {
- std::cout << "Enter bucket-size : ";
- int n;
- char ch;
- std::cin >> n;
- HashTable *table = new HashTable(n);
- while(true) {
- int choice = printMenu();
- ch = std::getchar(); // eat newline
- switch(choice) {
- case 1: // Insert a record
- {
- Student st;
- std::cout << "\nEnter Student Name : ";
- std::getline(std::cin, st.name);
- std::cout << "Enter Entry Number : ";
- std::getline(std::cin, st.entryNo);
- table->insert(st);
- break;
- }
- case 2: // search a Record
- {
- std::string entNum;
- std::cout << "\nEnter Entry Number: ";
- std::getline(std::cin, entNum);
- Student *st = table->search(entNum);
- std::cout << *st;
- std::cout << std::endl << "enter to continue ...";
- ch = std::getchar();
- break;
- }
- case 3: // delete a Record
- {
- std::string entNum;
- std::cout << "\nEnter Entry Number: ";
- std::getline(std::cin, entNum);
- table->remove(entNum);
- break;
- }
- case 4: // show All Records
- std::system("clear");
- table->print();
- std::cout << std::endl << "enter to continue ...";
- ch = std::getchar();
- break;
- case 5: // clear All Data
- delete table;
- table = new HashTable(n);
- break;
- case 6: // Exit
- goto DONE;
- }
- }
- DONE:
- delete table;
- credits();
- return 0;
- }
Monday, November 9, 2009
Extendible Hashing Implementation
Labels:
Computer Science,
data structures,
programming,
source
Subscribe to:
Posts (Atom)