0% found this document useful (0 votes)
7 views14 pages

hashing

dsa course

Uploaded by

Ishaq Shah
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views14 pages

hashing

dsa course

Uploaded by

Ishaq Shah
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

Lab 12 Hashing

Hash Table is a data structure which stores data in an associative manner. In a hash table, data is
stored in an array format, where each data value has its own unique index value. Access of data
becomes very fast if we know the index of the desired data.

Thus, it becomes a data structure in which insertion and search operations are very fast
irrespective of the size of the data. Hash Table uses an array as a storage medium and uses hash
technique to generate an index where an element is to be inserted or is to be located from.

Hashing

Hashing is a technique to convert a range of key values into a range of indexes of an array. We're
going to use modulo operator to get a range of key values. Consider an example of hash table of
size 20, and the following items are to be stored. Item are in the (key,value) format.

• (1,20)

• (2,70)

• (42,80)

• (4,25)

• (12,44)

• (14,32)

• (17,11)

• (13,78)

• (37,98)
Sr.No. Key Hash Array Index
1 1 1 % 20 = 1 1
2 2 2 % 20 = 2 2
3 42 42 % 20 = 2 2
4 4 4 % 20 = 4 4
5 12 12 % 20 = 12 12
6 14 14 % 20 = 14 14
7 17 17 % 20 = 17 17
8 13 13 % 20 = 13 13
9 37 37 % 20 = 17 17

Implementation of Hash Table


#include <iostream>
#include <vector>
using namespace std;

const int TABLE_SIZE = 10;

class HashTable {
private:
vector<int> table;
vector<bool> isOccupied;

// Hash Function
int hashFunction(int key) {
return key % TABLE_SIZE;
}

public:
// Constructor
HashTable() {
table.resize(TABLE_SIZE, -1); // Initialize table with -1 (empty)
isOccupied.resize(TABLE_SIZE, false); // Track occupied slots
}

// Insert a key into the hash table


void insert(int key) {
int index = hashFunction(key);
int i = 0;

// Resolve collision using Linear Probing


while (isOccupied[(index + i) % TABLE_SIZE]) {
i++;
if (i == TABLE_SIZE) { // Table is full
cout << "Hash Table is full, cannot insert " << key << endl;
return;
}
}

table[(index + i) % TABLE_SIZE] = key;


isOccupied[(index + i) % TABLE_SIZE] = true;
cout << "Inserted " << key << " at index " << (index + i) % TABLE_SIZE << endl;
}

// Search for a key in the hash table


int search(int key) {
int index = hashFunction(key);
int i = 0;

// Search using Linear Probing


while (isOccupied[(index + i) % TABLE_SIZE]) {
if (table[(index + i) % TABLE_SIZE] == key)
return (index + i) % TABLE_SIZE;
i++;
if (i == TABLE_SIZE) break; // Key not found
}
return -1; // Key not found
}

// Delete a key from the hash table


void remove(int key) {
int index = search(key);
if (index != -1) {
table[index] = -1; // Mark as empty
isOccupied[index] = false;
cout << "Removed " << key << " from index " << index << endl;
} else {
cout << "Key " << key << " not found!" << endl;
}
}

// Display the hash table


void display() {
for (int i = 0; i < TABLE_SIZE; i++) {
if (isOccupied[i])
cout << i << " --> " << table[i] << endl;
else
cout << i << " --> [Empty]" << endl;
}
}
};

int main() {
HashTable ht;
// Insert keys into the hash table
ht.insert(10);
ht.insert(20);
ht.insert(30);
ht.insert(25);

cout << "\nHash Table after insertions:" << endl;


ht.display();

// Search for a key


cout << "\nSearching for 25: ";
int result = ht.search(25);
if (result != -1)
cout << "Found at index " << result << endl;
else
cout << "Not Found" << endl;

// Delete a key
ht.remove(25);
cout << "\nHash Table after deletion:" << endl;
ht.display();

return 0;
}

Hash Collision
When the hash function generates the same index for multiple keys, there will be a conflict (what
value to be stored in that index). This is called a hash collision.

1. Collision resolution by chaining


In chaining, if a hash function produces the same index for multiple elements, these
elements are stored in the same index by using a doubly-linked list.

If j is the slot for multiple elements, it contains a pointer to the head of the list of elements.
If no element is present, j contains NIL.
Code
#include <iostream>
using namespace std;

const int TABLE_SIZE = 10; // Define the size of the hash table

// Node structure for the linked list


class Node {
public:
int key;
Node* next;

Node(int k) : key(k), next(nullptr) {} // Constructor to initialize a node


};

// Hash Table class


class HashTable {
private:
Node* table[TABLE_SIZE]; // Array of pointers to Nodes for chaining

// Hash Function
int hashFunction(int key) {
return key % TABLE_SIZE; // Modulo operation to determine index
}

public:
// Constructor to initialize the hash table
HashTable() {
for (int i = 0; i < TABLE_SIZE; i++) {
table[i] = nullptr; // Initialize all slots to null
}
}

// Insert a key into the hash table


void insert(int key) {
int index = hashFunction(key); // Calculate hash index
Node* newNode = new Node(key); // Create a new node with the key

// Insert at the beginning of the list at table[index]


newNode->next = table[index];
table[index] = newNode;

cout << "Inserted " << key << " at index " << index << endl;
}

// Search for a key in the hash table


bool search(int key) {
int index = hashFunction(key); // Calculate hash index
Node* current = table[index]; // Start at the head of the list

while (current) {
if (current->key == key) {
return true; // Key found
}
current = current->next; // Move to the next node
}
return false; // Key not found
}

// Delete a key from the hash table


void remove(int key) {
int index = hashFunction(key); // Calculate hash index
Node* current = table[index];
Node* prev = nullptr;

while (current) {
if (current->key == key) { // If key is found
if (prev) {
prev->next = current->next; // Bypass the node
} else {
table[index] = current->next; // Remove head node
}
delete current; // Free memory
cout << "Removed " << key << " from index " << index << endl;
return;
}
prev = current;
current = current->next;
}
cout << "Key " << key << " not found!" << endl;
}

// Display the hash table


void display() {
for (int i = 0; i < TABLE_SIZE; i++) {
cout << i << " --> ";
Node* current = table[i];
while (current) {
cout << current->key << " -> ";
current = current->next;
}
cout << "NULL" << endl;
}
}

// Destructor to clean up allocated memory


~HashTable() {
for (int i = 0; i < TABLE_SIZE; i++) {
Node* current = table[i];
while (current) {
Node* temp = current;
current = current->next;
delete temp;
}
}
}
};

int main() {
HashTable ht;

// Insert keys into the hash table


ht.insert(10);
ht.insert(20);
ht.insert(30);
ht.insert(25);
ht.insert(15);

cout << "\nHash Table after insertions:" << endl;


ht.display();

// Search for a key


cout << "\nSearching for 25: ";
if (ht.search(25))
cout << "Found" << endl;
else
cout << "Not Found" << endl;

// Delete a key
ht.remove(25);
cout << "\nHash Table after deletion:" << endl;
ht.display();

return 0;
}
i. Linear Probing As we can see, it may happen that the hashing technique is used to
create an already used index of the array. In such a case, we can search the next empty
location in the array by looking into the next cell until we find an empty cell. This
technique is called linear probing.
(hash(x) + 1) % S.

Array
Sr.No. Key Hash After Linear Probing, Array Index
Index
1 1 1 % 20 = 1 1 1
2 2 2 % 20 = 2 2 2
3 42 42 % 20 = 2 2 3
4 4 4 % 20 = 4 4 4
5 12 12 % 20 = 12 12 12
6 14 14 % 20 = 14 14 14
7 17 17 % 20 = 17 17 17
8 13 13 % 20 = 13 13 13
9 37 37 % 20 = 17 17 18
ii. Quadratic Probing It works similar to linear probing but the spacing between the slots
is increased (greater than one) by using the following relation.

h(k, i) = (h′(k) + c1i + c2i2) mod m

where,

c1 and c2 are positive auxiliary constants,

i = {0, 1, ….} (hash(x) + 1*1) % S


iii. Double hashing If a collision occurs after applying a hash function h(k), then another
hash function is calculated for finding the next slot.
h(k, i) = (h1(k) + ih2(k)) mod m
(hash(x) + 1*hash2(x)) % S
Code
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

const int TABLE_SIZE = 10;

enum CollisionResolution { LINEAR, QUADRATIC, DOUBLE_HASHING };

class HashTable {
private:
vector<int> table;
vector<bool> isOccupied;
CollisionResolution method;

// Hash Functions
int hashFunction(int key) {
return key % TABLE_SIZE;
}

int secondaryHashFunction(int key) {


return 7 - (key % 7); // Secondary hash for double hashing
}

public:
// Constructor
HashTable(CollisionResolution methodType) {
table.resize(TABLE_SIZE, -1);
isOccupied.resize(TABLE_SIZE, false);
method = methodType;
}

// Insert with selected collision resolution technique


void insert(int key) {
int index = hashFunction(key);
int i = 0;

while (isOccupied[(index + probeFunction(i, key)) % TABLE_SIZE]) {


i++;
if (i == TABLE_SIZE) {
cout << "Hash table is full, cannot insert " << key << endl;
return;
}
}

int finalIndex = (index + probeFunction(i, key)) % TABLE_SIZE;


table[finalIndex] = key;
isOccupied[finalIndex] = true;
cout << "Inserted " << key << " at index " << finalIndex << endl;
}

// Probe Function for Collision Resolution


int probeFunction(int i, int key) {
switch (method) {
case LINEAR:
return i; // Linear Probing
case QUADRATIC:
return i * i; // Quadratic Probing
case DOUBLE_HASHING:
return i * secondaryHashFunction(key); // Double Hashing
}
return 0; // Default (should not reach here)
}

// Search for a key


int search(int key) {
int index = hashFunction(key);
int i = 0;

while (isOccupied[(index + probeFunction(i, key)) % TABLE_SIZE]) {


int finalIndex = (index + probeFunction(i, key)) % TABLE_SIZE;
if (table[finalIndex] == key)
return finalIndex;
i++;
if (i == TABLE_SIZE)
break;
}
return -1; // Key not found
}

// Delete a key
void remove(int key) {
int index = search(key);
if (index != -1) {
table[index] = -1;
isOccupied[index] = false;
cout << "Removed " << key << " from index " << index << endl;
} else {
cout << "Key " << key << " not found!" << endl;
}
}

// Display the hash table


void display() {
for (int i = 0; i < TABLE_SIZE; i++) {
if (isOccupied[i])
cout << i << " --> " << table[i] << endl;
else
cout << i << " --> [Empty]" << endl;
}
}
};

int main() {
cout << "Choose Collision Resolution Method:\n";
cout << "1. Linear Probing\n2. Quadratic Probing\n3. Double Hashing\n";
int choice;
cin >> choice;

CollisionResolution method;
switch (choice) {
case 1:
method = LINEAR;
break;
case 2:
method = QUADRATIC;
break;
case 3:
method = DOUBLE_HASHING;
break;
default:
cout << "Invalid choice!" << endl;
return 0;
}

HashTable ht(method);

ht.insert(10);
ht.insert(20);
ht.insert(30);
ht.insert(25); // Collision resolved based on selected method
cout << "\nHash Table after insertions:" << endl;
ht.display();

cout << "\nSearching for 25: ";


int result = ht.search(25);
if (result != -1)
cout << "Found at index " << result << endl;
else
cout << "Not Found" << endl;

ht.remove(25);
cout << "\nHash Table after deletion:" << endl;
ht.display();

return 0;
}

Lab Tasks

After going through Lab tasks, submit a separate Word document which should

include all the results of the tasks Code should be in word and output should be

screenshot.

First page should contain your Full name, Registration #, Course name and Date

The File Should be saved with your name only.

No copied or AI Should be in Code or Explanation.

Case Study Task: Comprehensive Understanding of Hashing Techniques


Title: "Optimizing Data Storage and Retrieval with Hashing"

Objective:

To provide students with a hands-on learning experience to explore the concepts of hashing, including hash
functions, hash tables, and collision resolution techniques (chaining). Students will apply these concepts to
solve a real-world problem, analyze their effectiveness, and reflect on their findings.

Scenario:
Imagine you are part of a team developing a new e-commerce platform. The platform needs a fast and
efficient system to store and retrieve product data using unique product IDs. Each product ID is an integer
representing the product in the catalog. Due to a large number of products, collisions in the hash table are
unavoidable. Your task is to design and implement a hash table to handle these collisions effectively.

Tasks:

Part 1: Design the Hash Table

1. Create a hash table with a fixed size (e.g., 10 slots) to store integers (product IDs).

2. Implement a hash function:

Part 2: Collision Resolution Techniques

3. Implement and compare the following collision resolution techniques:

o Chaining

Part 3: Operations

4. Implement the following operations for each technique:

o Insert: Add a product ID to the hash table.

o Search: Find if a product ID exists in the hash table and return its index.

o Delete: Remove a product ID from the hash table.

Part 4: Testing and Analysis

5. Test your hash table by inserting the following product IDs in order: 10, 20, 30, 25, 35, 45, 50.

6. Perform the following operations:

o Search for 25 and 45.

o Delete 25 and 35.

o Display the hash table after each operation.

7. Compare the efficiency of the collision resolution techniques by measuring:

o The average time complexity of insert, search, and delete.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy