本文利用除留取余法+链地址法实现哈希表,并针对迅雷面试题写出相关代码。
一:哈希表
哈希表代码如下:
#ifndef _HASH_TABLE_H
#define _HASH_TABLE_H
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#define ElemType int
#define N 7
typedef struct HashNode{
ElemType m_data;
struct HashNode *link;
} HashNode, *HashTable[N];
/*
void init_htable(HashTable* pht) //自己的初始化方法
{
for(int i=0; i<N; ++i){
(*pht)[i] = (HashNode *)NULL;
}
}
*/
void init_htable(HashTable pht) //另一种初始化方法
{
for(int i=0; i<N; ++i){
pht[i] = NULL;
}
}
int hash_maker(ElemType key)
{
return key % N;
}
void insert_elem_front(HashTable pht, const ElemType val)
{
int index = hash_maker(val);
HashNode *new_node = (HashNode *)malloc(sizeof(HashNode));
assert(new_node != NULL);
new_node->m_data = val;
new_node->link = pht[index];
pht[index] = new_node;
}
void insert_elem_back(HashTable pht, const ElemType val)
{
int index = hash_maker(val);
HashNode *new_node = (HashNode *)malloc(sizeof(HashNode));
assert(new_node != NULL);
new_node->m_data = val;
new_node->link = NULL;
if(pht[index] == NULL){
pht[index] = new_node;
}
else{
HashNode *tmp = pht[index];
while(tmp->link != NULL)
tmp = tmp->link;
tmp->link = new_node;
}
}
HashNode* search_elem(HashTable pht, const ElemType target)
{
int index = hash_maker(target);
HashNode *tmp = pht[index];
while(tmp != NULL && tmp->m_data != target) //while(tmp!=NULL, tmp->data!=target)->segemention fault,逗号会同时计算表达式
tmp = tmp->link;
return tmp;
}
bool remove_elem(HashTable pht, const ElemType target)
{
HashNode* found = search_elem(pht, target);
if(found == NULL)
return false;
int index = hash_maker(target);
HashNode *tmp = pht[index];
if(tmp == found){
pht[index] = tmp->link;
}
else{
while(tmp->link != found){
tmp = tmp->link;
}
tmp->link = found->link;
}
free(found);
return true;
}
void show_htable(HashTable pht)
{
for(int i=0; i<N; ++i){
printf("%d ", i);
HashNode *tmp = pht[i];
while(tmp != NULL){
printf("%d->", tmp->m_data);
tmp = tmp->link;
}
printf("NULL\n");
}
}
void clear_htable(HashNode* tmp)
{
while(tmp != NULL){
HashNode *next_tmp = tmp->link;
free(tmp);
tmp = tmp->link;
}
}
void destroy_htable(HashTable pht)
{
for(int i=0; i<N; ++i){
clear_htable(pht[i]);
}
}
#endif
测试代码如下:
#include "Hash_Table.h"
int main()
{
ElemType array[] = {3, 43, 765, 4312, 431,
132, 65, 8, 32, 654};
HashTable ht;
//init_htable(&ht);
init_htable(ht);
size_t len = sizeof(array) / sizeof(ElemType);
for(int i=0; i<len; ++i)
insert_elem_back(ht, array[i]); //插入元素
printf("*************************insert*****************************\n");
show_htable(ht);
printf("*************************search*****************************\n");
printf("%p\n", search_elem(ht, 4312)); //查找元素
printf("*************************remove*****************************\n");
remove_elem(ht, 654); //删除元素
show_htable(ht);
printf("*************************destroy*****************************\n");
destroy_htable(ht); //摧毁Hash表
show_htable(ht);
return 0;
}
测试结果如下:
二:迅雷面试题
面试题大概是这样的:
现有一个用来存放整型的Hash表,Hash的存储单位成为桶,每个桶能存放3个整数,当一个桶要存放的数据超过3个时,则要将新的元素存放在溢出桶中,每个桶也能放三个元素,多个溢出桶用链表串联起来,此Hash表的基桶数目为素数P,Hash表的Hash函数对P取模。
下文是代码,P我自己习惯用N来表示。
#ifndef _HASH_TABLE_H
#define _HASH_TABLE_H
#define N 7
#define ElemType int
#define BUCKET_SIZE 3
#define NULL_DATA -1
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct bucket_node{
ElemType data[BUCKET_SIZE];
struct bucket_node *next;
} bucket_node, HashTable[N];
void init_htable(HashTable pht)
{
for(int i=0; i<N; ++i){
for(int j=0; j<BUCKET_SIZE; ++j){
pht[i].data[j] = NULL_DATA;
}
pht[i].next = NULL;
}
}
int hash_maker(ElemType key)
{
return key % N;
}
bool is_bucket_full(bucket_node *pbuck)
{
if(pbuck->data[BUCKET_SIZE-1] != NULL_DATA)
return true;
else
return false;
}
void insert_elem_final(bucket_node *pbuck, const ElemType val)
{
for(int i=0; i<BUCKET_SIZE; ++i){
if(pbuck->data[i] == NULL_DATA){
pbuck->data[i] = val;
break;
}
}
}
void insert_elem(HashTable pht, const ElemType val)
{
int index = hash_maker(val);
if(!is_bucket_full(&pht[index])){
insert_elem_final(&pht[index], val);
}
else{
bucket_node* pre_tmp = &pht[index];
bucket_node* tmp = pre_tmp->next;
while(tmp != NULL){
if(!is_bucket_full(tmp)){
insert_elem_final(tmp, val);
return ;
}
pre_tmp = tmp;
tmp = tmp->next;
}
bucket_node *new_node = (bucket_node *)malloc(sizeof(new_node));
assert(new_node != NULL);
new_node->data[0] = val;
new_node->data[1] = new_node->data[2] = NULL_DATA;
new_node->next = NULL;
pre_tmp->next = new_node;
}
return ;
}
void show_htable(HashTable ht)
{
for(int i=0; i<N; ++i){
printf("%d: ", i);
bucket_node *tmp = &ht[i];
while(tmp != NULL){
printf("{ ");
for(int j=0; j<BUCKET_SIZE; j++)
printf("%2d ", tmp->data[j]);
tmp = tmp->next;
printf("} ");
}
printf("\n");
}
}
#endif
下面是测试代码:
#include "HashTable.h"
int main()
{
ElemType array[] = {0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16,17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 1, 1, 1,};
//ElemType array[] = {6, 6, 6, 6};
HashTable ht;
init_htable(ht);
int len = sizeof(array) / sizeof(ElemType);
for(int i=0; i<len; ++i)
insert_elem(ht, array[i]);
show_htable(ht);
return 0;
}
结果如下: