哈希表,哈希算法(C语言)

哈希表

哈希表,又称散列表,常用于在海量数据中查找数据

哈希表中元素是由哈希函数确定的。将数据元素的关键字key作为自变量,通过一定的函数关系H(称为哈希函数),计算出的值,即为该元素的存储地址。其优点是:运算速度快;缺点是:基于数组、难于扩展,不可遍历。

在建立一个哈希表之前需要解决两个主要问题:

  1. 构造均匀的哈希函数
    使H(key)均匀分布在哈希表中,以提高地址计算的速度。
    构造哈希函数的方法:直接定址法,数字分析法,平法折中法,折叠法,除留余数法,随机数法等。
  2. 处理冲突
    冲突是指在哈希表中,不同的关键字值对应到同一个存储位置的现象。即存在K1≠K2,但H(K1)=H(K2)。
    再均匀的哈希函数都只能可减少冲突,但不可能避免冲突。
    发生冲突后,必须解决,即必须寻找下一个可用地址。
    解决冲突的方法:开放地址法(包括线性探测,二次探测,随机探测),再哈希法,链地址法,建立公共溢出区等。

C语言实现

哈希表的数据结构

typedef struct HashNode_Struct HashNode;  
struct HashNode_Struct  {  char* sKey;//键值指针int nValue;  //键值HashNode* pNext; //指向下一个哈希结构
};   

定义最大哈希长度及哈希数组

#define HASH_TABLE_MAX_SIZE 10000
HashNode* hashTable[HASH_TABLE_MAX_SIZE]; //哈希数组
int hash_table_size;  //当前哈希长度 

哈希表初始化函数

void hash_table_init()  
{  hash_table_size = 0;  memset(hashTable, 0 , sizeof(HashNode*) * HASH_TABLE_MAX_SIZE);//memset(void *s,int c,size_t n); //将s中后n个字节换成c所代表的内容 //该函数是对较大结构体或数组进行清零操作的一种最快的方法 
} 

去符号化函数

unsigned int hash_table_hash_str(const char* skey)  
{  //无符号unsigned能保存2倍与有符号类型的正整型数据 const signed char *p = (const signed char*)skey; //常量 unsigned int h = *p;  if(h){  for(p += 1; *p != '\0'; ++p)  h = (h << 5) - h + *p;  }  return h;  
}

插入函数

void hash_table_insert(const char* skey, int nvalue)  
{  if(hash_table_size >= HASH_TABLE_MAX_SIZE) //如果定义的哈希表长度大于等于最大长度 {  printf("内存溢出!\n");return;  }  unsigned int pos = hash_table_hash_str(skey) % HASH_TABLE_MAX_SIZE;  //用于解决冲突,pos为哈希函数 HashNode* pHead = hashTable[pos];while(pHead){  if(strcmp(pHead->sKey, skey) == 0)  {  printf("%s发生冲突!\n", skey);return ;  }  pHead = pHead->pNext;  }  //动态建立结点,初始化,分配内存空间 HashNode* pNewNode = (HashNode*)malloc(sizeof(HashNode));  memset(pNewNode, 0, sizeof(HashNode));  pNewNode->sKey = (char*)malloc(sizeof(char) * (strlen(skey) + 1));  strcpy(pNewNode->sKey, skey);  pNewNode->nValue = nvalue;  //指针后移 pNewNode->pNext = hashTable[pos];  hashTable[pos] = pNewNode;  //表长增加 hash_table_size++;  
}  

删除函数

void hash_table_remove(const char* skey)  
{  unsigned int pos = hash_table_hash_str(skey) % HASH_TABLE_MAX_SIZE; if(hashTable[pos])  {  HashNode* pHead = hashTable[pos];  HashNode* pLast = NULL;  HashNode* pRemove = NULL;  while(pHead)  {  if(strcmp(skey, pHead->sKey) == 0)  {   //若str1==str2,则返回零;//若str1>str2,则返回正数;//若str1<str2,则返回负数。 pRemove = pHead;//若相等,用pRemove记录  break; }  pLast = pHead;  //若不相等,不断后移 pHead = pHead->pNext;  }  if(pRemove)  {  if(pLast)pLast->pNext = pRemove->pNext;//实现删除1 else  hashTable[pos] = NULL;//实现删除2free(pRemove->sKey);  free(pRemove);  }  }  
}  

查找函数

HashNode* hash_table_lookup(const char* skey)  
{  unsigned int pos = hash_table_hash_str(skey) % HASH_TABLE_MAX_SIZE;  if(hashTable[pos])  {  HashNode* pHead = hashTable[pos];  while(pHead)  {  if(strcmp(skey, pHead->sKey) == 0)  return pHead;//查找成功 pHead = pHead->pNext;  }  }  return NULL;  
}  

打印哈希表函数

void hash_table_print()  
{ int i;  for(i = 0; i < HASH_TABLE_MAX_SIZE; ++i)  if(hashTable[i])//表不空 {  HashNode* pHead = hashTable[i];  printf("%d=>", i);  while(pHead)  {  printf("%s:%d  ", pHead->sKey, pHead->nValue);  pHead = pHead->pNext;  }  printf("\n");  }  
}  

释放内存函数

void hash_table_release()  
{  int i;  for(i = 0; i < HASH_TABLE_MAX_SIZE; ++i)  {  if(hashTable[i])  {  HashNode* pHead = hashTable[i];  while(pHead)  {  HashNode* pTemp = pHead;  pHead = pHead->pNext;  if(pTemp)  {  free(pTemp->sKey);  free(pTemp);  }  //逐个释放 }  }  }  
}  

随机生成函数

#define MAX_STR_LEN 20  
#define MIN_STR_LEN 10  
void rand_str(char r[])  
{  int i;  int len = MIN_STR_LEN + rand() % (MAX_STR_LEN - MIN_STR_LEN);  for(i = 0; i < len - 1; ++i)  r[i] = 'a' + rand() % ( 'z' - 'a');  r[len - 1] = '\0';  
}

具体代码如下:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <time.h>  #define HASH_TABLE_MAX_SIZE 10000  
typedef struct HashNode_Struct HashNode;  
struct HashNode_Struct  {  char* sKey;  int nValue;  HashNode* pNext;  
};  //哈希表数据结构 HashNode* hashTable[HASH_TABLE_MAX_SIZE]; 
int hash_table_size;  //哈希表中键值对的数量 //初始化哈希表 
void hash_table_init()  
{  hash_table_size = 0;  memset(hashTable, 0, sizeof(HashNode*) * HASH_TABLE_MAX_SIZE);//memset(void *s,int c,size_t n); //将s中后n个字节换成c所代表的内容 //该函数是对较大结构体或数组进行清零操作的一种最快的方法 
}  //去符号化哈希表  
unsigned int hash_table_hash_str(const char* skey)  
{  //无符号unsigned能保存2倍与有符号类型的正整型数据 const signed char *p = (const signed char*)skey; //常量 unsigned int h = *p;  if(h){  for(p += 1; *p != '\0'; ++p)  h = (h << 5) - h + *p;  }  return h;  
}
//插入 
void hash_table_insert(const char* skey, int nvalue)  
{  if(hash_table_size >= HASH_TABLE_MAX_SIZE) //如果定义的哈希表长度大于等于最大长度 {  printf("内存溢出!\n");return;  }  unsigned int pos = hash_table_hash_str(skey) % HASH_TABLE_MAX_SIZE;  //用于解决冲突,pos为哈希函数 HashNode* pHead = hashTable[pos];while(pHead){  if(strcmp(pHead->sKey, skey) == 0)  {  printf("%s发生冲突!\n", skey);return ;  }  pHead = pHead->pNext;  }  //动态建立结点,初始化,分配内存空间 HashNode* pNewNode = (HashNode*)malloc(sizeof(HashNode));  memset(pNewNode, 0, sizeof(HashNode));  pNewNode->sKey = (char*)malloc(sizeof(char) * (strlen(skey) + 1));  strcpy(pNewNode->sKey, skey);  pNewNode->nValue = nvalue;  //指针后移 pNewNode->pNext = hashTable[pos];  hashTable[pos] = pNewNode;  //表长增加 hash_table_size++;  
}  
//删除 
void hash_table_remove(const char* skey)  
{  unsigned int pos = hash_table_hash_str(skey) % HASH_TABLE_MAX_SIZE; if(hashTable[pos])  {  HashNode* pHead = hashTable[pos];  HashNode* pLast = NULL;  HashNode* pRemove = NULL;  while(pHead)  {  if(strcmp(skey, pHead->sKey) == 0)  {   //若str1==str2,则返回零;//若str1>str2,则返回正数;//若str1<str2,则返回负数。 pRemove = pHead;//若相等,用pRemove记录  break; }  pLast = pHead;  //若不相等,不断后移 pHead = pHead->pNext;  }  if(pRemove)  {  if(pLast)pLast->pNext = pRemove->pNext;//实现删除1 else  hashTable[pos] = NULL;//实现删除2free(pRemove->sKey);  free(pRemove);  }  }  
}  //查找 
HashNode* hash_table_lookup(const char* skey)  
{  unsigned int pos = hash_table_hash_str(skey) % HASH_TABLE_MAX_SIZE;  if(hashTable[pos])  {  HashNode* pHead = hashTable[pos];  while(pHead)  {  if(strcmp(skey, pHead->sKey) == 0)  return pHead;//查找成功 pHead = pHead->pNext;  }  }  return NULL;  
}  //打印 
void hash_table_print()  
{ int i;  for(i = 0; i < HASH_TABLE_MAX_SIZE; ++i)  if(hashTable[i])//表不空 {  HashNode* pHead = hashTable[i];  printf("%d=>", i);  while(pHead)  {  printf("%s:%d  ", pHead->sKey, pHead->nValue);  pHead = pHead->pNext;  }  printf("\n");  }  
}  //释放内存 
void hash_table_release()  
{  int i;  for(i = 0; i < HASH_TABLE_MAX_SIZE; ++i)  {  if(hashTable[i])  {  HashNode* pHead = hashTable[i];  while(pHead)  {  HashNode* pTemp = pHead;  pHead = pHead->pNext;  if(pTemp)  {  free(pTemp->sKey);  free(pTemp);  }  //逐个释放 }  }  }  
}  /* ============================主测试函数============================*/  
#define MAX_STR_LEN 20  
#define MIN_STR_LEN 10  
void rand_str(char r[])  
{  int i;  int len = MIN_STR_LEN + rand() % (MAX_STR_LEN - MIN_STR_LEN);  for(i = 0; i < len - 1; ++i)  r[i] = 'a' + rand() % ( 'z' - 'a');  r[len - 1] = '\0';  
}  int main(int argc, char** argv)  
{  srand(time(NULL));  hash_table_init();     int n = 10;  char str[MAX_STR_LEN + 1]; const char *key1 = "aaa111";  const char *key2 = "bbb222";  const char *key3 = "ccc333";while(n--)  {  rand_str(str);  hash_table_insert(str, n);  }printf("插入前\n");hash_table_print(); hash_table_insert(key1, 1);  hash_table_insert(key2, 2);  hash_table_insert(key3, 2);   printf("插入后\n");hash_table_print();  HashNode* pNode = hash_table_lookup(key1);  printf("查找结果:%d\n", pNode->nValue);  pNode = hash_table_lookup(key2);  printf("查找结果:%d\n", pNode->nValue);printf("删除之前:\n");  hash_table_print();  hash_table_remove(key3);  printf("删除之后:\n");  hash_table_print();  hash_table_release();  return 0;  
}  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569894.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【OP放大器】在不拆开OP放大器的情况下查一查它是否坏掉或饱和。

用高阻抗的示波器观测工作中的同相电压&#xff0b;点电压即可。 观测虚拟短路的点时&#xff0c;掌握工作中的诸条件&#xff0c;例如电源电压或周围温度的变化、负载的变动、对各种输入信号OP放大器及周边电路是否正常工作等&#xff0c;就可以得到很好的线索。转载于:https:…

Apache配置多个监听端口和访问网站的方法

一个apache服务器的vhost.conf配置文件可以设置Apache监听多个端口&#xff0c;打开Apache的配置文件httpd.conf&#xff0c;在 Listen 80 下面添加多个监听端口如&#xff1a; Listen 8010 Listen 8020 Listen 8030 这样就在vhosts.conf配置文件中增加了8010、8020和8030端…

图的邻接矩阵(C语言)

邻接矩阵 无向图和有向图在邻接矩阵中的表示方法&#xff1a; 无向图和有向图大同小异&#xff0c;在这里只以无向图为例&#xff0c;代码部分通过简单调整即可对应编译有向图 邻接矩阵数据类型定义 #define MaxVertices 100 //定义最大容量 typedef struct{ //包含权的邻…

MySQL安装成功后dos命令行设置密码

我在windows7上安装好MySQL数据库后&#xff0c;添加了MySQL的安装目录D:\wamp\MySQL\bin;到环境变量中&#xff0c;这样就可以在任何目录下使用mysql。为了安全性考虑&#xff0c;需要设置MySQL数据库的密码。通过dos命令行设置的方式如下&#xff1a; 一、进入dos命令行 按…

图的邻接表表示法(C语言)

邻接表 邻接表数据结构类型如下&#xff1a; #define MaxVertices 100 typedef struct node{ //边表 int adjvex;node* next; }EdgeNode; typedef struct{ //顶点表 int vertex; EdgeNode* edgenext; }VertexNode; typedef VertexNode AdjList[MaxVertices];//…

最小生成树构造算法--Prim算法,Kruskal算法(C语言)

最小生成树 最小生成树&#xff08;minimum spanning tree&#xff09;是由n个顶点&#xff0c;n-1条边&#xff0c;将一个连通图连接起来&#xff0c;且使权值最小的结构。 最小生成树可以用Prim&#xff08;普里姆&#xff09;算法或kruskal&#xff08;克鲁斯卡尔&#xff…

屏蔽烦人的百度搜索热点

开发时&#xff0c;在百度上搜索一些资料时&#xff0c;总是不经意看到百度搜索热点的一些新闻&#xff0c;然后经不住诱惑的标题就不经意间点了进去&#xff0c;然后就是连锁反应了。。等再次回到开发时已经是半小时之后的事了。又要把想要的东西重新捋一遍&#xff0c;导致开…

矩阵在竞赛中的应用

矩阵乘法代码&#xff1a; struct matrix {int n, m;int a[100][100]; }; // A.m B.n matrix matrix_mul(matrix A, matrix B) {matrix C;C.n A.n;C.m B.m;for (int i 0; i < A.n; i) {for (int j 0; j < B.m; j) {C.a[i][j] 0;for (int k 0; k < A.m; k) {C.a…

连通图遍历策略之广度优先搜索(C语言)

广度优先搜素&#xff08;BFS&#xff09; 广度优先搜索(又称宽度优先搜索)算法是最简便的图的搜索算法之一&#xff0c;该算法属于一种盲目搜寻法&#xff0c;目的是系统地展开并检查图中的所有节点&#xff0c;以找寻结果。换句话说&#xff0c;它并不考虑结果的可能位置&am…

多条件组合查询

一、效果图 二、前端代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8" /> <title>Jquery分类</title> <script src"http://libs.baidu.com/jquery/1.7.2/jquery.min.js"></sc…

“三次握手,四次挥手”你真的懂吗?

记得刚毕业找工作面试的时候&#xff0c;经常会被问到&#xff1a;你知道“3次握手&#xff0c;4次挥手”吗&#xff1f;这时候我会“胸有成竹”地“背诵”前期准备好的“答案”&#xff0c;第一次怎么怎么&#xff0c;第二次……答完就没有下文了&#xff0c;面试官貌似也没有…

连通图遍历策略之深度优先搜索(C语言)

深度优先搜素&#xff08;DFS&#xff09; 深度优先搜索是一种在开发爬虫早期使用较多的方法。它的目的是要达到被搜索结构的叶结点(即那些不包含任何超链的HTML文件) 。在一个HTML文件中&#xff0c;当一个超链被选择后&#xff0c;被链接的HTML文件将执行深度优先搜索&#…

PHP+cURL扩展的使用

PHP 支持 Daniel Stenberg 创建的 libcurl 库&#xff0c;能够连接通讯各种服务器、使用各种协议。libcurl 目前支持的协议有 http、https、ftp、gopher、telnet、dict、file、ldap。 libcurl 同时支持 HTTPS 证书、HTTP POST、HTTP PUT、 FTP 上传(也能通过 PHP 的 FTP 扩展完…

dwc_otg驱动 BUG: sleeping function called from invalid context at mm/page_alloc.c

方案商的开发板上otg功能只能做device&#xff0c;硬件看过后说没有5v供电&#xff0c;加上后能够识别U盘了&#xff0c;但是内核报了错 [ 3.264000] usb 2-1: new high-speed USB device number 2 using dwc_otg[ 3.280000] BUG: sleeping function called from invalid conte…

单源最短路径之迪杰斯特拉算法(C语言)

Dijkstra&#xff08;迪杰斯特拉&#xff09;算法 采用广度优先搜索思想&#xff0c;对有向赋权图寻找最短路径。 该算法对于不含负权的有向图来说&#xff0c;是目前已知的最快的单源最短路径算法。 时间复杂度&#xff1a;O&#xff08;n^2&#xff09; 基本原理&#xf…

PHP_VERSION获取php版本

PHP_VERSION PHP_VERSION&#xff1a;当前PHP的版本号。 <?phpecho PHP_VERSION; ?>结果&#xff1a;5.4.45 很多时候我们只需要获取大的版本号就够用了&#xff0c;因为大的版本号决定了很多新的特性和函数。因此用substr()函数获取前三位字符。 <?phpecho su…

全源最短路径之弗洛伊德算法(C语言)

Floyd&#xff08;弗洛伊德&#xff09;算法 该算法是解决任意两点间的最短路径的一种算法&#xff0c;可以正确处理有向图或负权&#xff08;但不可存在负权回路)的最短路径问题&#xff0c;同时也被用于计算有向图的传递闭包。 时间复杂度为 O&#xff08;N^3&#xff09; …

Mybatis主线流程源码解析

Mybatis的基础使用以及与Spring的相关集成在官方文档都写的非常详细&#xff0c;但无论我们采用xml还是注解方式在使用的过程中经常会出现各种奇怪的问题&#xff0c;需要花费大量的时间解决。 抽空了解一下Mybatis的相关源码还是很有必要。 先来看一个简单的Demo&#xff1a; …

动态规划之背包问题(C语言)

动态规划 动态规划&#xff08;英语&#xff1a;Dynamic programming&#xff0c;简称DP&#xff09;是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构性质的问题 动态规划思想大致上为&#xff1a;若要解一…

PHP函数-判断字符是否在于指定的字符串中

php中判断一个字符是否在字符串中 1、函数 以下四个函数都可以用来判断字符串中是否存在待查询的字符&#xff0c;可以是数字、字母或者符号。 strpos() - 查找字符串在另一字符串中第一次出现的位置&#xff08;区分大小写&#xff09; stripos() - 查找字符串在另一字符…