// Beispiel zur Veranschaulichung einer Hash-Funktion // (c) 05/97 Gottfried Rudorfer #include <iostream.h> #include <new.h> extern "C" { // for exit() #include <stdlib.h> // for strcpy() and strlen() #include <string.h> } // forward reference class Table; class Element { public: friend class Table; Element(char *key, char *value); ~Element(); private: char *key; char *value; Element *next; }; class Table { public: Table(unsigned int s, unsigned int m); ~Table(); void Put(char *key, char *value); void Print(); void Delete(char *key); char *Get(char *key); private: unsigned int Hash(char *key); unsigned int hash_mult, hash_size; //array of pointers to Element Element **hash_table; }; // Konstruktor mit zwei Argumenten Element::Element(char *new_key, char *new_value) { // +1 für das terminierende '\0' !! key = new char [strlen(new_key)+1]; value = new char [strlen(new_value)+1]; strcpy(key, new_key); strcpy(value, new_value); next = NULL; } // Destruktor für obigen Konstruktor Element::~Element() { // lösche zuerst das nächste Listenelement, // soferne es vorhanden ist. delete key; delete value; } // Konstruktor mit zwei Argumenten Table::Table(unsigned int s, unsigned int m) { hash_size = s; hash_mult = m; // Array von Pointern auf Instanzen der Klasse Element // Die Instanzen werden hier nicht erzeugt. hash_table = new Element* [hash_size]; for(unsigned int i=0; i<hash_size; i++) hash_table[i] = NULL; } // Destruktor für obigen Konstruktor Table::~Table() { Element *e, *n; //n ist die Adresse zum nächsten Element // lösche zuerst die linked lists for(unsigned int i=0; i<hash_size; i++) { e=hash_table[i]; while(e != NULL) { n=e->next; delete e; e=n; } } // lösche die Hash-Tabelle // [] bei delete ist notwendig, wenn ein benutzerdefinierter // Typ an der Adresse gespeichert ist. delete [] hash_table; } unsigned int Table::Hash(char *p) { unsigned long hash_val = 0; for(; *p; p++) hash_val = hash_val * hash_mult + *p; hash_val %= hash_size; return hash_val; } void Table::Put(char *new_key, char *new_value) { unsigned int hash_val = Hash(new_key); Element *p, *e = hash_table[hash_val]; if (e == NULL) { // new list hash_table[hash_val] = \ new Element(new_key, new_value); } else { while(e != NULL) { if (!strcmp(new_key, e->key)) { // key found, replace value delete e->value; e->value = new char [strlen(new_value)+1]; strcpy(e->value, new_value); return; } else { p = e; e = e->next; } } // new element at the end of list p->next = new Element(new_key, new_value); } } char *Table::Get(char *existing_key) { int hash_val = Hash(existing_key); Element *e = hash_table[hash_val]; while(e != NULL) { if (!strcmp(existing_key, e->key)) return(e->value); else e = e->next; } // Der Key wurde nicht in der Hash-Tabelle gefunden. return NULL; } void Table::Delete(char *existing_key) { int hash_val = Hash(existing_key); Element *e = hash_table[hash_val]; Element *p=NULL; while(e != NULL) { if (!strcmp(existing_key, e->key)) { if (p == NULL) { // first element if (e->next == NULL) { // list contains only one element hash_table[hash_val] = NULL; } else { // second element ist now first hash_table[hash_val] = e->next; } } else { // other elements (not first) if (e->next == NULL) { // last element p->next = NULL; } else { // element in the middle of list p->next = e->next; } } delete e; return; } p = e; e = e->next; } cout << "Element not found!" << endl; } void Table::Print() { Element *e; unsigned int j; for (unsigned int i = 0; i < hash_size; i++) { cout << i << ":"; e = hash_table[i]; j = 0; while(1) { cout << " listelem " << j; if (e == NULL) { cout << ": NULL "; break; } else { cout << ": key: " << e->key \ << " value: " << e->value; j++; e = e->next; } } cout << endl; } } void NoSpace() { cerr << "New Failed" << endl; exit(1); } main() { // Rufe die Funktion NoSpace() auf // wenn new keinen freien Speicher // belegen kann set_new_handler(NoSpace); unsigned int size; Table *hash = NULL; char key_buffer[128], value_buffer[128]; char c, *result; cout << "** Hashing Example **" <<endl; while(1) { cout << "0) Hash-Tabelle erzeugen;" << endl; cout << "1) enter new key and value;" << endl; cout << "2) display value behind key;" << endl; cout << "3) display hash-table;" << endl; cout << "4) delete entry;" << endl; cout << "5) Hash-Tabelle zerstören;" <<endl; cout << "9) end program;" << endl; cin >>c; switch(c) { case '0': cout << "enter size of Hash-Table "; cin >> size; if (size == 0) { cerr << "Kann eine Hash-Tabelle der Größe 0 nicht anlegen" << endl; break; } hash = new Table(size, 65559); break; case '1': if (hash == NULL) { cerr << "Es existiert noch keine Hash-Tabelle" << endl; break; } cout << "enter key "; cin >> key_buffer; cout << "enter value "; cin >> value_buffer; hash->Put(key_buffer, value_buffer); break; case '2': if (hash == NULL) { cerr << "Es existiert noch keine Hash-Tabelle" << endl; break; } cout << "enter key "; cin >> key_buffer; result = hash->Get(key_buffer); if (NULL == result) { cout << "key " << key_buffer << " "; cout << "does not exist" << endl; } else { cout << "value for " << key_buffer; cout << " is " << result <<endl; } break; case '3': if (hash == NULL) { cerr << "Es existiert noch keine Hash-Tabelle" << endl; break; } hash->Print(); break; case '4': if (hash == NULL) { cerr << "Es existiert noch keine Hash-Tabelle" << endl; break; } cout << "enter key "; cin >> key_buffer; hash->Delete(key_buffer); break; case '5': delete hash; hash=NULL; break; case '9': exit(0); default: cout << "unknown command!" << endl; } } }
© 1997 Gottfried Rudorfer, C++-AG, Lehrveranstaltungen, Abteilung für Angewandte Informatik, Wirtschaftsuniversität Wien, 6/4/1998 |