一、字符串转换
youhua.h
//哈希函数的优化: //一、将静态的改为动态 # pragma once # include<stdio.h> # include<string.h> # include<stdlib.h> # include<assert.h> #define MAX_SIZE 10 typedef int DataType; typedef enum{ EXIST, EMPTY, DELETE }State; typedef struct HTElem { DataType _data; State _state; }HTElem; typedef struct HashTable { HTElem *_array;//改为动态 int _capacity;//容量 int _size;//计算哈希表中有效元素的个数 int _IsLineDetective;//是否为线性探测 }HashTable, HT; void HashTableInit(HT *ht, int capacity,int IsLineDetetive); void HashTableInsert(HT *ht, DataType data); //删除 void HashTableDelete(HT *ht, DataType data); //查找 int HashTableFind(HT *ht, DataType data); void Detective2(int hashAddr, int i);//二次探测 int DetectiveLine(int hashAddr);//线性探测 void Swap(HT *lht, HT *rht); //计算哈希表格中的元素个数 int HashTableSize(HT *ht); //判断哈希表格是不是空的 int HashTableEmpty(HT *ht); int CheckCapacity(HT *ht); void HashTableDestroy(HT *ht); int HashFunc(DataType data);
youhua.c
# include"youhua.h" # include"Common.h" void HashTableInit(HT *ht, int capacity, int IsLineDetetive) { int i = 0; ht->_array = (HTElem*)malloc(capacity*sizeof(HTElem));//开辟空间:变为动态的 if (NULL == ht->_array) { assert(0); return; } //把位置给成空 for (; i < capacity; ++i) ht->_array[i]._state = EMPTY; ht->_size = 0; ht->_capacity = capacity; ht->_IsLineDetective = IsLineDetetive; } void HashTableInsert(HT *ht, DataType data) { int hashAddr = -1; int i = 0; assert(ht); if (!CheckCapacity(ht)) return; HashTableDestroy(&data); //计算哈希地址 hashAddr = HashFunc(data); } int CheckCapacity(HT *ht) { assert(ht); //开辟新空间 if (ht->_size * 10 / ht->_capacity >= 7)//判断是否增容:与哈希负载因子比较 { int NewCapacity = ht->_capacity * 2;//新容量增容到旧容量的两倍 /*HTElem *pTmp = (HTElem*)malloc(NewCapacity*sizeof(DataType)); if (NULL == pTmp) { assert(0); return 0; }*/ // HT NewHt;//新哈希表 int i = 0; HashTableInit(&NewHt, NewCapacity, ht->_IsLineDetective); //拷贝元素(旧哈希表中的有效元素插入新哈希表) for (; i < ht->_size; ++i) { if (ht->_array[i]._state == EXIST) HashTableInsert(&NewHt, ht->_array[i]._data);//将旧哈希表中i号位置的元素插入新哈希标中 } Swap(&ht, &NewHt);//交换新哈希表和旧哈希表中的内容 HashTableDestroy(&NewHt);//销毁新哈希表的内容 } return 1; } void Swap(HT *lht, HT *rht) { int tmp; assert(lht); assert(rht); //交换capacity tmp = lht->_capacity; lht->_capacity = rht->_capacity; rht->_capacity = tmp; //交换size tmp = lht->_size; lht->_size = rht->_size; rht->_size = tmp; //交换IsDetective tmp = lht->_IsLineDetective; lht->_IsLineDetective = rht->_IsLineDetective; rht->_IsLineDetective = tmp; //交换array tmp = (int)lht->_array; lht->_array = rht->_array; rht->_array = (HTElem*)tmp; } void HashTableDestroy(HT *ht) { assert(ht); if (ht->_array)//如果有空间 { free(ht->_array);//释放空间 ht->_array = NULL; ht->_capacity = 0;//容量清零 ht->_size = 0; } } void HashTableDelete(HT *ht, DataType data) { int ret = -1; assert(ht); ret = HashTableFind(ht, data); if (-1 != ret) { ht->_array[ret]._state = DELETE; ht->_size--; } } //查找 int HashTableFind(HT *ht, DataType data) { int hashAddr = -1; int startAddr = -1;//开始查找的地址 int i = 0; assert(ht); hashAddr = HashFunc(data); startAddr = hashAddr; while (ht->_array[hashAddr]._state != EMPTY) { if (EXIST == ht->_array[hashAddr]._state) { if (data == ht->_array[hashAddr]._data) return hashAddr; } //hashAddr++;//没有找到,继续往后找 //if (hashAddr == MAX_SIZE)//越界了,从头再找 // hashAddr = 0; //if (hashAddr == startAddr)//哈希地址等于开始查找的起始地址,说明找了一圈都没有找到 // return -1; if (ht->_IsLineDetective) { DetectiveLine(hashAddr); //找了一圈没有找到 if (hashAddr == startAddr) return -1; } else Detective2(hashAddr, ++i); } return -1;//没有找到 } //计算哈希表格中的元素个数 int HashTableSize(HT *ht) { return ht->_size; } //判断哈希表格是不是空的 int HashTableEmpty(HT *ht) { assert(ht); return 0 == ht->_size; } int DetectiveLine(int hashAddr)//线性探测 { hashAddr++; if (hashAddr == MAX_SIZE) hashAddr = 0; return hashAddr; } void Detective2(int hashAddr, int i)//二次探测 { hashAddr = hashAddr + 2 * i + 1; if (hashAddr >= MAX_SIZE)//越界了 hashAddr %= MAX_SIZE;//越界之后模回来 return hashAddr; } int HashFunc(DataType data) { return StrToInt(data) % MAX_SIZE; }
common.h
# pragma once typedef unsigned int size_t;//# include<stddef.h> ////字符串转换为整型 unsigned int StrToInt(const char * str);
common.c
# define _CRT_SECURE_NO_WARNINGS 1 # include"Common.h" unsigned int StrToInt(const char * str) { unsigned int seed = 131; // 31 131 1313 13131 131313 unsigned int hash = 0; while (*str) { hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF); }
二、使用素数进行除留取余法
sushu.h
//哈希函数的优化: //一、将静态的改为动态 # ifndef __SUSHU_H__ # define __SUSHU_H__ # include<stdio.h> # include<string.h> # include<stdlib.h> # include<assert.h> #define MAX_SIZE 10 typedef int DataType; typedef enum{ EXIST, EMPTY, DELETE }State; typedef struct HTElem { DataType _data; State _state; }HTElem; typedef struct HashTable { HTElem *_array;//改为动态 int _capacity;//容量 int _size;//计算哈希表中有效元素的个数 int _IsLineDetective;//是否为线性探测 }HashTable, HT; void HashTableInit(HT *ht, int capacity, int IsLineDetetive); void HashTableInsert(HT *ht, DataType data); //删除 void HashTableDelete(HT *ht, DataType data); //查找 int HashTableFind(HT *ht, DataType data); void Detective2(int hashAddr, int i);//二次探测 int DetectiveLine(int hashAddr);//线性探测 void Swap(HT *lht, HT *rht); //计算哈希表格中的元素个数 int HashTableSize(HT *ht); //判断哈希表格是不是空的 int HashTableEmpty(HT *ht); int CheckCapacity(HT *ht); void HashTableDestroy(HT *ht); int HashFunc(DataType data); #endif
sushu.c
# include"sushu.h" # include"Common.h" void HashTableInit(HT *ht, int capacity, int IsLineDetetive) { int i = 0; ht->_array = (HTElem*)malloc(capacity*sizeof(HTElem));//开辟空间:变为动态的 if (NULL == ht->_array) { assert(0); return; } //把位置给成空 for (; i < capacity; ++i) ht->_array[i]._state = EMPTY; ht->_size = 0; ht->_capacity = capacity; ht->_IsLineDetective = IsLineDetetive; } void HashTableInsert(HT *ht, DataType data) { int hashAddr = -1; int i = 0; assert(ht); if (!CheckCapacity(ht)) return; HashTableDestroy(&data); //计算哈希地址 hashAddr = HashFunc(data); } int CheckCapacity(HT *ht) { assert(ht); //开辟新空间 if (ht->_size * 10 / ht->_capacity >= 7)//判断是否增容:与哈希负载因子比较 { int NewCapacity = GetNextPrime(ht->_capacity*2);//新容量增容到旧容量的两倍 /*HTElem *pTmp = (HTElem*)malloc(NewCapacity*sizeof(DataType)); if (NULL == pTmp) { assert(0); return 0; }*/ // HT NewHt;//新哈希表 int i = 0; HashTableInit(&NewHt, NewCapacity, ht->_IsLineDetective); //拷贝元素(旧哈希表中的有效元素插入新哈希表) for (; i < ht->_size; ++i) { if (ht->_array[i]._state == EXIST) HashTableInsert(&NewHt, ht->_array[i]._data);//将旧哈希表中i号位置的元素插入新哈希标中 } Swap(&ht, &NewHt);//交换新哈希表和旧哈希表中的内容 HashTableDestroy(&NewHt);//销毁新哈希表的内容 } return 1; } void Swap(HT *lht, HT *rht) { int tmp; assert(lht); assert(rht); //交换capacity tmp = lht->_capacity; lht->_capacity = rht->_capacity; rht->_capacity = tmp; //交换size tmp = lht->_size; lht->_size = rht->_size; rht->_size = tmp; //交换IsDetective tmp = lht->_IsLineDetective; lht->_IsLineDetective = rht->_IsLineDetective; rht->_IsLineDetective = tmp; //交换array tmp = (int)lht->_array; lht->_array = rht->_array; rht->_array = (HTElem*)tmp; } void HashTableDestroy(HT *ht) { assert(ht); if (ht->_array)//如果有空间 { free(ht->_array);//释放空间 ht->_array = NULL; ht->_capacity = 0;//容量清零 ht->_size = 0; } } void HashTableDelete(HT *ht, DataType data) { int ret = -1; assert(ht); ret = HashTableFind(ht, data); if (-1 != ret) { ht->_array[ret]._state = DELETE; ht->_size--; } } //查找 int HashTableFind(HT *ht, DataType data) { int hashAddr = -1; int startAddr = -1;//开始查找的地址 int i = 0; assert(ht); hashAddr = HashFunc(data); startAddr = hashAddr; while (ht->_array[hashAddr]._state != EMPTY) { if (EXIST == ht->_array[hashAddr]._state) { if (data == ht->_array[hashAddr]._data) return hashAddr; } //hashAddr++;//没有找到,继续往后找 //if (hashAddr == MAX_SIZE)//越界了,从头再找 // hashAddr = 0; //if (hashAddr == startAddr)//哈希地址等于开始查找的起始地址,说明找了一圈都没有找到 // return -1; if (ht->_IsLineDetective) { DetectiveLine(hashAddr); //找了一圈没有找到 if (hashAddr == startAddr) return -1; } else Detective2(hashAddr, ++i); } return -1;//没有找到 } //计算哈希表格中的元素个数 int HashTableSize(HT *ht) { return ht->_size; } //判断哈希表格是不是空的 int HashTableEmpty(HT *ht) { assert(ht); return 0 == ht->_size; } int DetectiveLine(int hashAddr)//线性探测 { hashAddr++; if (hashAddr == MAX_SIZE) hashAddr = 0; return hashAddr; } void Detective2(int hashAddr, int i)//二次探测 { hashAddr = hashAddr + 2 * i + 1; if (hashAddr >= MAX_SIZE)//越界了 hashAddr %= MAX_SIZE;//越界之后模回来 return hashAddr; } int HashFunc(DataType data) { return StrToInt(data) % MAX_SIZE; }
common.h
# pragma once typedef unsigned int size_t;//# include<stddef.h> size_t GetNextPrime(int capacity); unsigned int StrToInt(const char * str);
common.c
//闭散列用的少,因为浪费空间 # define _CRT_SECURE_NO_WARNINGS 1 # include"Common.h" #define _PrimeSize 28//enum{_PrimeSize =28}; // 使用素数表对齐做哈希表的容量,降低哈希冲突 const unsigned long _PrimeList[_PrimeSize]= {//可将long换为long long获取更大的素数 53ul, 97ul, 193ul, 389ul, 769ul, 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457u, 1610612711ul, 3221225473ul, 4294967291ul }; //获取比容量大的第一个素数 size_t GetNextPrime(size_t capacity) { int i = 0; for (; i < _PrimeSize; ++i) { if (_PrimeList[i]>capacity)//容量小于素数,直接返回该素数 return _PrimeList[i]; } return _PrimeList[_PrimeSize - 1];//容量太大了,返回最后一个素数 } unsigned int StrToInt(const char * str) { unsigned int seed = 131; // 31 131 1313 13131 131313 unsigned int hash = 0; while (*str) { hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF); }
test.c
# include"sushu.h" void TestHashTable() { HashTable ht; HashTableInit(&ht, 10, 1); HashTableInsert(&ht, "欧阳锋"); HashTableInsert(&ht, "李某某"); HashTableInsert(&ht, "哈哈"); HashTableInsert(&ht, "会话"); } int main() { TestHashTable(); system("pause"); return 0; }