基于分离链接法的哈希表实现

/*
  哈希表
    基本操作 :
      - 创建空的哈希表
      - 查找 key 对应的 value
      - 插入键值对 ( 分离链接法)

*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
// hashTable 地址空间存放的结构体
typedef struct Node* pointerNode;
// hashTable 结构体
typedef struct HashTable* pointerHashTable;



// 操作函数 -------------------------------

int nextPrimeNumber(int n);

pointerHashTable initializeTable(int tableSize);

int hashFunction(pointerHashTable hashTable, int key);

pointerNode findBySeparateChaining(pointerHashTable hashTable, char* key);

int insertBySeparateCaining(pointerHashTable hashTable, char* key);

void printHashTable(pointerHashTable hashTable);

// end -----------------------------------


// hashTable 地址空间的状态

typedef struct Node {
  char key[15];
  pointerNode next;
}Node;
typedef struct HashTable {
  int tableSize;
  Node* head;
} HashTable;


// 获取一个不小于 n 的最小素数
int nextPrimeNumber(int n) {
  // 素数不会被大于一的数整除
  // 首先排除偶数, 在奇数里面找

  int p = (n % 2) ? n : n + 1;

  int maxNum = 10000;
  while (p < 10000) {
    // 书上这里i 的取值范围是 sqrt(p)-2 ,真的精悍
    int i = p - 1;
    for (;i > 1;i--) {
      if (0 == p % i) {
        break;
      }
    }
    if (i == 1) {
      return p;
    }
    p += 2;
  }
  return -1;
}
// 初始化哈希表
// 这里表的大小为比 tableSize 大的最小素数
// 哈希表数组元素为 Node
pointerHashTable initializeTable(int tableSize) {
  int size = nextPrimeNumber(tableSize);
  printf("next prime number = %d\n", nextPrimeNumber(tableSize));

  pointerHashTable hashTable = (pointerHashTable)malloc(sizeof(HashTable));
  hashTable->head = (pointerNode)malloc(size * sizeof(Node));
  hashTable->tableSize = size;

  for (int i = 0;i < size;i++) {
    hashTable->head[i].key[i] = '\0';
    hashTable->head[i].next = NULL;
  }
  printf("initialize end\n");
  return hashTable;
}
// 哈希函数
// 使用除留余数法
int hashFunction(pointerHashTable hashTable, int key) {
  return key % hashTable->tableSize;
}
// 查找 key
// 使用分离链接法
pointerNode findBySquare(pointerHashTable hashTable, char* key) {
  // 先把字符串 key 使用移位法处理一下赋值给 hashKey ,不然冲突太严重  
  int hashKey = 0;
  for(int i =0;i<strlen(key);i++){
    int index = i;
    int intKey = key[strlen(key)-1-i];
    while(index>0){
      intKey = intKey << 5;
      index--;
    }
    hashKey += intKey;
  }
  
  // 使用哈希函数获取下标
  int currentPosition = hashFunction(hashTable, hashKey);
  pointerNode currentNode = hashTable->head[currentPosition].next;
  pointerNode resultNode = (pointerNode)malloc(sizeof(Node));
  
  resultNode->key[0] = '\0';
  resultNode->next = NULL;

  if(currentNode==NULL){
    hashTable->head[currentPosition].next = resultNode;
    return resultNode;
  }
  
  while (currentNode->next != NULL && strcmp(currentNode->key, key) != 0) {
    printf("哈希冲突 ");
    currentNode = currentNode->next;
  }
  // hashtable 找到相同的 key
  if (strcmp(currentNode->key, key) == 0) {
    printf("find same key");
    return currentNode;
  } else {
    // 没找到就加新结点
    currentNode->next = resultNode;
    return resultNode;
  }
}
// 插入 key
// 使用分离链接法
int insertBySquare(pointerHashTable hashTable, char* key) {
  // 先看一下表里面有没有这个键值对
  pointerNode node = findBySquare(hashTable, key);
  if (strcmp(node->key, key) == 0) {
    return -1;
  } else {
    strcpy(node->key, key);
    return 0;
  }

}

// 输出键值对
// 实际只有 key 没有 value
void printHashTable(pointerHashTable hashTable) {
  printf("\n");
  for (int i = 0;i < hashTable->tableSize;i++) {
    pointerNode node = hashTable->head[i].next;
    printf("hash index %d = ",i);
    while (node != NULL) {
      printf("%s ", node->key);
      node = node->next;
    }
    printf("\n");
  }
}
int main() {
  pointerHashTable hashTable = initializeTable(80);

  // 测试一下分离链接法
  int x = 8;
  char str[15] = "\0";
  for (int i = 0;i < 98;i++) {
    x += i;
    sprintf(str, "%d ", x);
    insertBySquare(hashTable, str);
  }
   printHashTable(hashTable);
    //
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值