Sunteți pe pagina 1din 9

Sheet 5

1)We hash each key : home address =key % hashsize , then we insert the key at the home address.
If other keys exist, the key is inserted at the start of the list
0 26 13
1
2 15 2
3 16 3
4
5 18 5
6

2)Number of steps = number of key comparisons


We hash the key and start at the home address
9:0
26:1
16:1
3)
int hash(string s,int hashsize)
{
int h=0;
for (int i=0;i<s.length();i++)h=h*2+s[i];
return h%hashsize;
}
To call this function:
int h=hash(s,hashsize); //where s is a string

Optional:
Overloading %:
int operator%(string s,int hashsize)
{
int h=0;
for (int i=0;i<s.length();i++)h=h*2+s[i];
return h%hashsize;
}
This means that we will give the operator % a new meaning only when it has operands of the specified
types (left operand is string, right is int)
To call this function:
int h=s%hashsize;
Note that this doesn't affect the original meaning of % when given two integers (5%4 will still give 1)

4) Linear probing.
Remember that we insert nodes in the table at the home address. A collision means that 2 keys will
have the same home address. If collision occurs we will start at the home address and look for the next free
slot after it.
Note that in this implementation, a variable called slotStatus is associated with each slot.
It determines whether the slot is empty, in use or deleted.
Assume that a key (k1) has home address of 5. If the slot 5 is empty, k1 will be inserted at slot number 5.
If another key (k2) to be inserted has the same home address 5 (collision), it will try to find the first
slot that is not in use starting from 5, assume 6 is empty it will be inserted at 6.
Now assume that the first key (k1) is deleted. And we want to look for k2. We will start searching at its
home address 5. If we don't have the slot status to tell us that a key was deleted from slot 5, we will
assume that k2 doesn't exist. However knowing that a key was deleted from slot 5, we start looking in
the following slots, until we either find k2, or find a slot whose status is empty, so we conclude that the
key doesn't exist.

const int MAX_TABLE = 11;


template < class tableKeyType, class tableDataType >
class Table
{
public:
Table( ); // Table constructor
void insert(const tableKeyType & key, const tableDataType & data);
// Precondition: None
// Postcondition: data and associated key are stored in the Table,
// i.e., lookup(key,data) == true and returns the data
// Note: If there was already data stored with this key, the insert call will replace it.

bool lookup(const tableKeyType & key, tableDataType & data);


// Precondition: None
// Postcondition: if key is in the table, returns true and associated
// data is returned; otherwise, false is returned and data is undefined.

void deleteKey(const tableKeyType & key);


// Precondition: None
// Postcondition: lookup(key,d) returns false

void dump(); // print the contents of the hash table


private:
enum slotType {Empty, Deleted, InUse}; //enum defines a type that takes only specified values
struct slot {
slotType slotStatus; // slotStatus is a variable of type slotType that takes only Empty, Deleted, or
InUse
tableKeyType key;
tableDataType data;
};
slot T[MAX_TABLE]; // stores the items in the table
int entries; // keep track of number of entries in table
int hash(const tableKeyType & key);
// Precondition: none
// Postcondition: none
// Returns: the home address for key

int probe(const int pos);


// Precondition: pos is a slot between 0 and MAX_TABLE-1
// Postcondition: none
// Returns: the next slot, using wrapping (between 0 and MAX_TABLE-1)

bool search(int & pos, const tableKeyType & target);


// Precondition: pos is the hash address of target
// Postcondition: if target is in the table, pos is set to its actual slot
// Returns: true if target is in the table, else false
};

template < class tableKeyType, class tableDataType >


int
Table < tableKeyType, tableDataType >
::hash(const tableKeyType & key)
{
return key % MAX_TABLE;
}

template < class tableKeyType, class tableDataType >


int
Table < tableKeyType, tableDataType >
::probe(const int pos)
{
if (pos < MAX_TABLE - 1)
return pos + 1;
else // when we reach the end of the array, we start at the beginning
return 0;
}
template < class tableKeyType, class tableDataType >
bool
Table < tableKeyType, tableDataType >
::search(int & pos, const tableKeyType & target)
{
for ( ; T[pos].slotStatus != Empty; pos = probe(pos))
if (T[pos].slotStatus == InUse && T[pos].key == target)
return true;
return false;
}
In the previous function, we search for the target starting at pos.
Note that pos is passed by reference since we want to change it.
If target is found pos will hold its index. If we reach an empty slot, this means that the key doesn't exist.
Note that the for loop doesn't have initial condition

template < class tableKeyType, class tableDataType >


Table < tableKeyType, tableDataType >
::Table( ) // implementation of Table constructor
{
entries = 0;
int i;
for (i = 0; i < MAX_TABLE; i++)
T[i].slotStatus = Empty;
}

template < class tableKeyType, class tableDataType >


void
Table < tableKeyType, tableDataType >
::insert(const tableKeyType & key, const tableDataType & data)
{
assert(entries < MAX_TABLE - 1);
int pos(hash(key)); // find a position to insert the item
if (!search(pos, key)) { // key was not in the table
// starting at home address, find first free position
pos = hash(key);
while (T[pos].slotStatus == InUse)
pos = probe(pos);
entries++; // number of entries goes up
}
//Now pos is the index where we will insert the key.
T[pos].slotStatus = InUse;
T[pos].key = key;
T[pos].data = data;
}
In the previous function, we check first that after inserting the slot, there will still be at least one empty slot
in the table. This is needed since search() searches until it finds an empty slot then it stops.
Then we hash the key and start searching at the home address.
We call search(): It will be executed in any case.
If the key is in the table (search returns true), pos will contain its index.
If the key is not in the table (search returns false), we adjust pos at the first place that is not InUse, to insert
the key.
Note that search() gets the first empty slot, but here we need the first empty or deleted slot (whichever
comes first) to insert the new key and data.
In both cases the code after the if statement is executed to insert the key.
template < class tableKeyType, class tableDataType >
bool
Table < tableKeyType, tableDataType >
::lookup(const tableKeyType & key, tableDataType & data)
{
int pos(hash(key)); // hash the key
if (search(pos, key)) { // start searching at pos
data = T[pos].data; // put the data in the variable ‘data’ that is passed by reference
return true;
}
else
return false;
}

template < class tableKeyType, class tableDataType >


void
Table < tableKeyType, tableDataType >::deleteKey(const tableKeyType & key)
{
int pos(hash(key));
if (search(pos, key)) {
T[pos].slotStatus = Deleted;
entries--;
}
}

template < class tableKeyType, class tableDataType >


void
Table < tableKeyType, tableDataType >::dump()
{
int i;
for (i = 0; i < MAX_TABLE; i++) {
cout << i << '\t'; // tab (some spaces)
switch(T[i].slotStatus) {
case InUse:
cout << "In Use\t" << T[i].key << endl;
break;
case Deleted:
cout << "Deleted\t" << T[i].key << endl;
break;
case Empty:
cout << "Empty\t" << endl;
break;
}
}
cout << "Entries = " << entries << "\n\n";
}
5)
Implementing the chained hash table using linked list.
The table will be an array of Linked lists.
Each entry of the array will contain the member variables of the list (head, tail, and current).
Initially each entry of the array (each linked list) will be empty (head, tail and current =0, and there won’t be
any nodes).
As we insert in a certain link list, a node will be allocated (outside the array of course) and head and tail of
that list will point to the allocated nodes.
Advantages of using linked lists: We will not have to implement the linked list from scratch, we will reuse
the code that we wrote before for linked lists. Also the code will be cleaner and more simple since we will
use functions instead of dealing with pointers.
Disadvantages : There will be time overhead since we have to call functions. Dealing directly with pointers
is faster. Also each entry in the array will contain (head, tail and current) instead of one pointer.
Also we will have to add member functions to the linked list class to handle deleting and changing data in
nodes (since first(), next(), and insert() can’t do that).

Code for table class:


#include"list.h" //(note that we will use a templated linked list class)
const int MAX_TABLE = 11;
template < class tableKeyType, class tableDataType >
class Table
{
public:
// Table(); we don’t need a constructor, since the constructor of list class will cause each head, tail and
// current to be=0
void insert(const tableKeyType & key, const tableDataType & data);
bool lookup(const tableKeyType & key, tableDataType & data);
void deleteKey(const tableKeyType & key);
void dump();
private:

struct Slot
{
tableKeyType key;
tableDataType data;
};

List<Slot> T[MAX_TABLE]; // array of linked lists


int hash(const tableKeyType & key);
};

template <class tableKeyType, class tableDataType>


int Table<tableKeyType,tableDataType>::hash(const tableKeyType & key)
{
return key % MAX_TABLE;
}

template < class tableKeyType, class tableDataType >


void Table<tableKeyType,tableDataType>::insert(const tableKeyType & key, const tableDataType & data)
{
int pos(hash(key));
Slot s,s1;
s1.key=key;s1.data=data;
bool f=T[pos].first(s);
if(f==false)T[pos].insert(s1); //if the list is empty
else
{
while(f)
{ // if the key exists, update slot
if(s.key==key){T[pos].UpdateCurrent(s1);return;}
f=T[pos].next(s);
}
// if key doesn't exist, insert slot at beginning
T[pos]. InsertAtBeginning (s1);
}
}

template < class tableKeyType, class tableDataType >


bool Table<tableKeyType,tableDataType>::lookup(const tableKeyType & key, tableDataType & data)
{
int pos(hash(key));
Slot s; bool b;
b=T[pos].first(s);
while(b)
{
if(s.key==key)
{data=s.data;return true;}
b=T[pos].next(s);
}
return false;
}
In the previous function, we hash the key, traverse the list comparing the keys. Remember that s is passed
by reference to first () and next() so after the call they contain an element (a slot) from the list.

template < class tableKeyType, class tableDataType >


void Table < tableKeyType, tableDataType >::deleteKey(const tableKeyType & key)
{
int pos(hash(key));

Slot s; bool b;
b=T[pos].first(s);
while(b)
{
if(s.key==key)
{T[pos].deleteCurrent();return;}
b=T[pos].next(s);
}
}
// deleteCurrent() is a member function that we will add to the linked list class that will delete the node to
which 'current' points.

template < class tableKeyType, class tableDataType >


void Table<tableKeyType,tableDataType>::dump()
{
Slot s;bool b;
for (int i=0; i < MAX_TABLE; i++)
{
cout << i << '\t';
b=T[i].first(s);
while(b)
{
cout<<s.key<<'\t';
b=T[i].next(s);
}
cout << '\n';
}
cout << '\n';
}
In the previous function, each iteration of the for loop traverses one of the lists printing the keys.

Code for the list :

#include<assert.h>
template <class ListElementType>
class List
{
public:
List();
void insert(const ListElementType & elem);
bool first(ListElementType & elem);
bool next(ListElementType & elem);

void UpdateCurrent(const ListElementType & e);


void InsertAtBeginning(const ListElementType & e);
void deleteCurrent();

private:
struct Node;
typedef Node *Link;
struct Node
{
ListElementType elem;
Link next;
};
Link head;
Link tail;
Link current;
};

template <class ListElementType>


List<ListElementType>::List()
{
head = 0;
tail = 0;
current = 0;
}
/////first(), next(), and insert() will be the same . We only put [ template <class ListElementType> ] before
each function and the class name used is [ List<ListElementType> ] like:
template <class ListElementType>
void List<ListElementType>::insert(const ListElementType & elem)
//// member functions that we add:
template <class ListElementType>
void List<ListElementType>::UpdateCurrent(const ListElementType & e)
{
assert(current);
current->elem=e;
}

template <class ListElementType>


void List<ListElementType>::InsertAtBeginning(const ListElementType & e)
{
Link addedNode=new Node;
addedNode->next=head;
addedNode->elem=e;
head=addedNode;
}

template <class ListElementType>


void List<ListElementType>::deleteCurrent()
{
assert(current);
if(head==0)return; // list is empty
Link del; // if current is at head
if(head==current)
{
del=current;
head=current->next;
current=current->next;
delete del;
return;
}
// current is not at the first node
for(Link p=head;p->next!=current;p=p->next);
del=current;
p->next=current->next;
current=current->next;
delete del;
}

S-ar putea să vă placă și