使用 C 哈希表的 DSA


概述

哈希表是一种数据结构,无论哈希表的大小如何,插入和搜索操作都非常快。它几乎是一个常数或 O(1)。哈希表使用数组作为存储介质,利用哈希技术生成要插入或定位元素的索引。

散列

散列是一种将一系列键值转换为一系列数组索引的技术。我们将使用模运算符来获取一系列键值。考虑一个大小为 20 的哈希表的示例,并且要存储以下项目。项目采用(键,值)格式。

  • (1,20)

  • (2,70)

  • (42,80)

  • (4,25)

  • (12,44)

  • (14,32)

  • (17,11)

  • (13,78)

  • (37,98)

先生。 钥匙 哈希值 数组索引
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 号

线性探测

正如我们所看到的,所使用的哈希技术可能会创建已使用的数组索引。在这种情况下,我们可以通过查看下一个单元格来搜索数组中的下一个空位置,直到找到空单元格。这种技术称为线性探测。

先生。 钥匙 哈希值 数组索引 线性探测后,数组索引
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

基本操作

以下是哈希表的基本主要操作。

  • 搜索- 搜索哈希表中的元素。

  • 插入- 在哈希表中插入一个元素。

  • 删除- 从哈希表中删除一个元素。

数据项

定义一个具有一些数据的数据项,以及要在哈希表中进行搜索的键。

struct DataItem {
   int data;   
   int key;
};

哈希方法

定义一个哈希方法来计算数据项的键的哈希码。

int hashCode(int key){
   return key % SIZE;
}

搜索操作

每当要搜索元素时。计算传递的键的哈希码,并使用该哈希码作为数组中的索引来定位元素。如果在计算的哈希码中未找到元素,则使用线性探测来获取前面的元素。

struct DataItem *search(int key){               
   //get the hash 
   int hashIndex = hashCode(key);        
   
   //move in array until an empty 
   while(hashArray[hashIndex] !=NULL){
      if(hashArray[hashIndex]->key == key)
         return hashArray[hashIndex]; 
      //go to next cell
      ++hashIndex;
      //wrap around the table
      hashIndex %= SIZE;
   }
   return NULL;        
}

插入操作

每当要插入元素时。计算传递的键的哈希码,并使用该哈希码作为数组中的索引来定位索引。如果在计算的哈希码处找到元素,则对空位置使用线性探测。

void insert(int key,int data){
   struct DataItem *item = (struct DataItem*) malloc(sizeof(struct DataItem));
   item->data = data;  
   item->key = key;     

   //get the hash 
   int hashIndex = hashCode(key);

   //move in array until an empty or deleted cell
   while(hashArray[hashIndex] !=NULL &&
      hashArray[hashIndex]->key != -1){
      //go to next cell
      ++hashIndex;
      //wrap around the table
      hashIndex %= SIZE;
   }
   hashArray[hashIndex] = item;        
}

删除操作

每当要删除一个元素时。计算传递的键的哈希码,并使用该哈希码作为数组中的索引来定位索引。如果在计算的哈希码中未找到元素,则使用线性探测来获取前面的元素。找到后,将虚拟项存储在那里以保持哈希表的性能完好无损。

struct DataItem* delete(struct DataItem* item){
   int key = item->key;

   //get the hash 
   int hashIndex = hashCode(key);

   //move in array until an empty 
   while(hashArray[hashIndex] !=NULL){
      if(hashArray[hashIndex]->key == key){
         struct DataItem* temp = hashArray[hashIndex]; 
         
         //assign a dummy item at deleted position
         hashArray[hashIndex] = dummyItem; 
         return temp;
      }               
      //go to next cell
      ++hashIndex;
      //wrap around the table
      hashIndex %= SIZE;
   }
   return NULL;        
}

例子

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

#define SIZE 20

struct DataItem {
   int data;   
   int key;
};

struct DataItem* hashArray[SIZE]; 
struct DataItem* dummyItem;
struct DataItem* item;

int hashCode(int key){
   return key % SIZE;
}

struct DataItem *search(int key){               
   //get the hash
   int hashIndex = hashCode(key);        
   
   //move in array until an empty 
   while(hashArray[hashIndex] !=NULL){
      if(hashArray[hashIndex]->key == key)
         return hashArray[hashIndex]; 
      //go to next cell
      ++hashIndex;
      //wrap around the table
      hashIndex %= SIZE;
   }        
   return NULL;        
}

void insert(int key,int data){
   struct DataItem *item = (struct DataItem*) malloc(sizeof(struct DataItem));
   item->data = data;  
   item->key = key;     

   //get the hash 
   int hashIndex = hashCode(key);

   //move in array until an empty or deleted cell
   while(hashArray[hashIndex] !=NULL &&
      hashArray[hashIndex]->key != -1){
      //go to next cell
      ++hashIndex;
      //wrap around the table
      hashIndex %= SIZE;
   }
   hashArray[hashIndex] = item;        
}
struct DataItem* delete(struct DataItem* item){
   int key = item->key;

   //get the hash 
   int hashIndex = hashCode(key);

   //move in array until an empty 
   while(hashArray[hashIndex] !=NULL){
      if(hashArray[hashIndex]->key == key){
         struct DataItem* temp = hashArray[hashIndex]; 
         //assign a dummy item at deleted position
         hashArray[hashIndex] = dummyItem; 
         return temp;
      }
      //go to next cell
      ++hashIndex;
      //wrap around the table
      hashIndex %= SIZE;
   }
   return NULL;        
}
void display(){
   int i=0;
   for(i=0; i<SIZE; i++) {
      if(hashArray[i] != NULL)
         printf(" (%d,%d)",hashArray[i]->key,hashArray[i]->data);
      else
         printf(" ~~ ");
   }
   printf("\n");
}
int main(){
   dummyItem = (struct DataItem*) malloc(sizeof(struct DataItem));
   dummyItem->data = -1;  
   dummyItem->key = -1; 

   insert(1, 20);
   insert(2, 70);
   insert(42, 80);
   insert(4, 25);
   insert(12, 44);
   insert(14, 32);
   insert(17, 11);
   insert(13, 78);
   insert(37, 97);

   display();
   item = search(37);

   if(item != NULL){
      printf("Element found: %d\n", item->data);
   } else {
      printf("Element not found\n");
   }

   delete(item);
   item = search(37);

   if(item != NULL){
      printf("Element found: %d\n", item->data);
   } else {
      printf("Element not found\n");
   }
}

如果我们编译并运行上面的程序,那么它将产生以下结果 -

 ~~  (1,20)  (2,70)  (42,80)  (4,25)  ~~  ~~  ~~  ~~  ~~  ~~  ~~ (12,44)  (13,78)  (14,32)  ~~  ~~  (17,11)  (37,97)  ~~ 
Element found: 97
Element not found