哈希表的查询程序(50单词查询)
- 格式:docx
- 大小:14.43 KB
- 文档页数:4
哈希表查找(散列表查找)c++实现HashMap算法思想:哈希表什么是哈希表在前⾯讨论的各种结构(线性表、树等)中,记录在结构中的相对位置是随机的,和记录的关键字之间不存在确定的关系,因此,在结构中查找记录时需进⾏⼀系列和关键字的⽐较。
这⼀类查找⽅法建⽴在“⽐较”的基础上。
在顺序查找时,⽐较的结果为“="与“!=”两种可能;在折半查找、⼆叉排序树查找和B树查找时,⽐较的结果为“<"、"="和“>"3种可能。
查找的效率依赖于查找过程中所进⾏的⽐较次数。
理想的情况是希望不经过任何⽐较,⼀次存取便能得到所查记录,那就必须在记录的存储位置和它的关键字之间建⽴⼀个确定的对应关系f,使每个关键字和结构中⼀个惟⼀的存储位置相对应。
因⽽在查找时,只要根据这个对应关系f找到给定值K的像f(K)。
若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上,由此,不需要进⾏⽐较便可直接取得所查记录。
在此,我们称这个对应关系f为哈希( Hash)函数,按这个思想建⽴的表为哈希表。
哈希函数的构造⽅法哈希函数是从关键字集合到地址集合的映像。
通常,关键字集合⽐较⼤,它的元素包括所有可能的关键字,⽽地址集合的元素仅为哈希表中的地址值。
哈希函数其实是⼀个压缩映像,那么这种情况就不可避免的产⽣冲突,那么在建造哈希表时不仅要设定⼀个好的哈希函数,还要设定⼀种处理冲突的⽅法。
(设定的哈希函数H(key)和处理冲突的⽅法将⼀组关键字映像到⼀个有限的连续的地址集上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这种表就是哈希表,映像的过程为哈希造表或散列,所得的存储位置称哈希地址或散列地址)(1)直接定址法取关键字或关键字的某个线性函数值为哈希地址。
即H(key)=key 或 H(key)=a*key+b (a,b为常数)。
举例1:统计1-100岁的⼈⼝,其中年龄作为关键字,哈希函数取关键字⾃⾝。
哈希表(Hash)的查找一、哈希表相关概念1、哈希函数的基本概念哈希表又称散列表。
哈希表存储的基本思想是:以数据表中的每个记录的关键字 k为自变量,通过一种函数H(k)计算出函数值。
把这个值解释为一块连续存储空间(即数组空间)的单元地址(即下标),将该记录存储到这个单元中。
在此称该函数H为哈希函数或散列函数。
按这种方法建立的表称为哈希表或散列表。
理想情况下,哈希函数在关键字和地址之间建立了一个一一对应关系,从而使得查找只需一次计算即可完成。
由于关键字值的某种随机性,使得这种一一对应关系难以发现或构造。
因而可能会出现不同的关键字对应一个存储地址。
即k1≠k2,但H(k1)=H(k2),这种现象称为冲突。
把这种具有不同关键字值而具有相同哈希地址的对象称“同义词”。
在大多数情况下,冲突是不能完全避免的。
这是因为所有可能的关键字的集合可能比较大,而对应的地址数则可能比较少。
对于哈希技术,主要研究两个问题:(1)如何设计哈希函数以使冲突尽可能少地发生。
(2)发生冲突后如何解决。
2、哈希函数的构造方法常见的构造方法有很多种,如直接定址法,数字分析法,平方取中法等。
接下来,我们介绍其中的几种:(1)除留余数法取关键字k被某个不大于表长m的数p除后所得余数作为哈希函数地址的方法。
即:H(k)=k mod p这种方法的关键是选择好p。
使得数据集合中的每一个关键字通过该函数转化后映射到哈希表的任意地址上的概率相等。
理论研究表明,一般取p为小于m的最大质数或不包含小于20的质因素的合数。
(2)平方取中法先将关键字平方,然后取其中间几位作为散列地址。
所取位数由地址空间范围决定。
若地址空间小于所取位数值决定的范围,可通过乘以一比例因子来解决。
(3)折叠法把关键字分割成位数相等(最后一部分的位数可以不同)的几部分,然后通过折叠后将几部分进行相加,丢掉进位位,所得值即为散列地址。
散列的位数由地址空间的位数而定。
分割方法:从右至左相加方法有两种:移位叠加:将分割后的各部分低位对齐相加。
123456789101112131415161718123456789101112131415161718 // HashTableInitializeTable(int TableSize) {HashTable H;int i;// 為散列表分配空間// 有些编譯器不支持為struct HashTable 分配空間,聲稱這是一個不完全的結構,// 可使用一个指向HashTable的指針為之分配空間。
// 如:sizeof(Probe),Probe作为HashTable在typedef定義的指針。
H = malloc(sizeof(struct HashTable));// 散列表大小为一个質数H->TableSize = Prime;// 分配表所有地址的空間H->Cells = malloc(sizeof(Cell) * H->TableSize);// 地址初始為空for (i =0; i < H->TableSize; i++)H->Cells[i].info = Empty;return H;}查找空单元并插入:// PositionFind(ElementType Key, HashTable H) {Position Current;int CollisionNum;// 冲突次数初始为0// 通過表的大小對關鍵字進行處理CollisionNum =0;Current = Hash( Key, H->TableSize );// 不為空時進行查詢while (H->Cells[Current].info != Empty &&H->Cells[Current].Element != Key) {Current =++CollosionNum *++CollisionNum;// 向下查找超過表範圍時回到表的開頭if (Current >= H->TableSize)Current -= H->TableSize;}return Current;}分離連接法散列表的查找过程基本上和造表过程相同。
哈希表查找方法原理(一)哈希表查找方法简介什么是哈希表?•哈希表是一种用于存储键值对(key-value)数据的数据结构。
•哈希表的本质是一个数组,每个数组元素称为一个桶(bucket)或槽(slot)。
•每个桶可以存储一个或多个键值对,通过使用哈希函数将键映射为桶的索引。
哈希函数的作用•哈希函数将任意大小的数据映射到固定大小的值。
•这个值作为索引用于访问哈希表中特定桶的位置。
•好的哈希函数应该具备以下特点:–确定性:对于相同的输入,哈希函数应始终返回相同的哈希值。
–均匀性:哈希值应尽可能地分布均匀,避免冲突。
–高效性:哈希函数应具备高效计算的特点,以提高查找效率。
哈希表的查找方法1.哈希表查找的基本过程:–通过哈希函数计算出要查找元素的哈希值。
–使用哈希值作为索引,在哈希表中访问对应的桶。
–检查桶中的元素,进行比较以确定是否找到目标元素。
2.根据桶内元素的存储方式,哈希表的查找方法可分为两种基本类型:a.链地址法(拉链法)–桶中的每个位置都是一个链表,用于存储哈希值相同的键值对。
–查找时,首先计算哈希值,然后在相应的链表中顺序查找目标元素。
–链地址法适合处理冲突较多的情况,但链表过长会影响查找效率。
b.开放地址法(线性探测法、二次探测法等)–桶中的每个位置都可以存储一个键值对。
–当发生冲突时,通过一定的方法找到下一个可用的桶来存储冲突的元素。
–常用的探测方法包括线性探测、二次探测等。
–开放地址法适合处理冲突较少的情况,但可能会造成桶的利用率低下。
哈希表查找的时间复杂度•在理想情况下,哈希表的查找时间复杂度为O(1)。
•但在最坏情况下,查找时间复杂度可能会达到O(n),其中n为待查找元素的总数。
•好的哈希函数和适当的处理冲突方法可以尽量降低冲突的发生,提高查找效率。
总结•哈希表通过哈希函数将键映射为桶的索引,实现了高效的查找操作。
•哈希表的查找方法主要有链地址法和开放地址法,根据具体情况选择合适的方法。
详解哈希表的查找哈希表和哈希函数在记录的存储位置和它的关键字之间是建立一个确定的对应关系(映射函数),使每个关键字和一个存储位置能唯一对应。
这个映射函数称为哈希函数,根据这个原则建立的表称为哈希表(Hash Table),也叫散列表。
以上描述,如果通过数学形式来描述就是:若查找关键字为key,则其值存放在f(key) 的存储位置上。
由此,不需比较便可直接取得所查记录。
注:哈希查找与线性表查找和树表查找最大的区别在于,不用数值比较。
冲突若key1 ≠ key2 ,而f(key1) = f(key2),这种情况称为冲突(Collision)。
根据哈希函数f(key)和处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这一映射过程称为构造哈希表。
构造哈希表这个场景就像汽车找停车位,如果车位被人占了,只能找空的地方停。
构造哈希表由以上内容可知,哈希查找本身其实不费吹灰之力,问题的关键在于如何构造哈希表和处理冲突。
常见的构造哈希表的方法有 5 种:(1)直接定址法说白了,就是小学时学过的一元一次方程。
即 f(key) = a * key + b。
其中,a和b 是常数。
(2)数字分析法假设关键字是R进制数(如十进制)。
并且哈希表中可能出现的关键字都是事先知道的,则可选取关键字的若干数位组成哈希地址。
选取的原则是使得到的哈希地址尽量避免冲突,即所选数位上的数字尽可能是随机的。
(3)平方取中法取关键字平方后的中间几位为哈希地址。
通常在选定哈希函数时不一定能知道关键字的全部情况,仅取其中的几位为地址不一定合适;而一个数平方后的中间几位数和数的每一位都相关,由此得到的哈希地址随机性更大。
取的位数由表长决定。
(4)除留余数法取关键字被某个不大于哈希表表长 m 的数 p 除后所得的余数为哈希地址。
即f(key) = key % p (p ≤ m)这是一种最简单、最常用的方法,它不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。
哈希查找的流程Hash lookup is a fundamental algorithm used in computer science to quickly retrieve data from a large dataset. The process involves using a hash function to map data to a unique key, which is then used to store and retrieve the data efficiently.哈希查找是计算机科学中使用的基本算法,用于从大型数据集中快速检索数据。
该过程涉及使用哈希函数将数据映射到唯一键,然后使用该键来高效地存储和检索数据。
From a technical perspective, the first step in a hash lookup process is to apply a hash function to the search key. This generates a unique hash value that is used as an index to access the corresponding data in a hash table. The hash table is a data structure that stores key-value pairs and allows for constant-time retrieval of data.从技术角度来看,哈希查找过程中的第一步是对搜索键应用哈希函数。
这将生成一个唯一的哈希值,该值用作索引来访问哈希表中的相应数据。
哈希表是一种存储键值对的数据结构,可以实现数据的常数时间检索。
One of the key advantages of hash lookup is its efficiency in retrieving data, especially in large datasets. This is because the use of a hash function allows for constant-time access to data, regardless of the size of the dataset. As a result, hash lookup is commonly used in applications where quick data retrieval is crucial, such as database systems and information retrieval systems.哈希查找的一个关键优势是它在检索数据方面的效率,特别是在大型数据集中。
#include <conio.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define szNAME 100
#define HASH_ROOT 74 /*用于计算哈希地址的随机数*/
#define szHASH 80 /*哈希表总长度*/
#define COUNT 50 /*单词总数*/
/*哈希表结构体*/
struct THash {
int key; /*钥匙码*/
char word[20]; /*单词*/
int depth; /*检索深度*/
};
/*根据钥匙码和哈希根计算哈希地址*/
int GetHashAddress(int key, int root)
{
return key % root;
}/*end GetHashAddress*/
/*冲突地址计算,如果发现地址冲突,则用当前地址和钥匙码、哈希根重新生成一个新地址*/
int GetConflictAddress(int key, int address, int root)
{
int addr = address + key % 5 + 1;
return addr % root;
}/*end GetConflictAddress*/
/*根据字符串生成哈希钥匙码,这里的方法是将串内所有字符以数值形式求累加和*/
int CreateKey(char * word)
{
int key = 0;
unsigned char * n = (unsigned char *)word;
while(*n) key += *n++;
return key;
}/*end CreateKey*/
/*输入一个单词,并返回哈希钥匙码*/
int GetName(char * word)
{
scanf("%s", word);
return CreateKey(word);
}/*end CreateKey*/
/*根据单词个数、长度和哈希根构造哈希表*/
struct THash * CreateNames(int size, int root, int count)
{
int i =0, key = 0, addr = 0, depth = 0; char word[20];
struct THash * h = 0, *hash = 0;
/*哈希根和长度不能太小*/
if(size < root || root < 2) return 0;
/*根据哈希表长度构造一个空的哈希表*/
hash = (struct THash *)malloc(sizeof(struct THash) * size);
/*将整个表清空*/
memset(hash, 0, sizeof(struct THash) * size);
for(i = 0; i < count; i++) {
/*首先产生一个随机的单词,并根据单词计算哈希钥匙码,再根据钥匙码计算地址*/ key = GetName(word);
addr = GetHashAddress(key, root);
h = hash + addr;
if (h->depth == 0) { /*如果当前哈希地址没有被占用,则存入数据*/
h->key = key;
strcpy(h->word , word);
h->depth ++;
continue;
}/*end if*/
/*如果哈希地址已经被占用了,就是说有冲突,则寻找一个新地址,直到没有被占用*/ depth = 0;
while(h->depth ) {
addr = GetConflictAddress(key, addr, root);
h = hash + addr;
depth ++;
}/*end while*/
/*按照新地址存放数据,同时记录检索深度*/
h->key = key;
strcpy(h->word , word);
h->depth = depth + 1;
}/*next*/
return hash;
}/*end CreateNames*/
/*在哈希表中以特定哈希根查找一个单词的记录*/
struct THash * Lookup(struct THash * hash, char * word, int root)
{
int key = 0, addr = 0; struct THash * h = 0;
/*不接受空表和空名称*/
if(!word || !hash) return 0;
key = CreateKey(word);
addr = GetHashAddress(key, root);
h = hash + addr;
/*如果结果不正确表示按照冲突规则继续寻找*/
while(strcmp(h->word , word)) {
addr = GetConflictAddress(key, addr, root);
h = hash + addr;
if(h->key == 0) return 0;
}/*end while*/
return hash + addr;
}/*end Lookup*/
/*根据一条哈希表记录打印该单词的信息*/
void Print(struct THash * record)
{
if (!record) {
printf("【查无单词】\n");
return ;
}/*end if*/
if(record->depth)
printf("【单词】%s\t【检索深度】%d\n", record->key, record->word, record->depth ); else
printf("【空记录】\n");
/*end if*/
}/*end Print*/
/*打印单词表*/
void Display(struct THash * hash, int size)
{
struct THash * h = 0;
if (!hash || size < 1) return ;
printf("单词表:\n");
printf("--------------------\n");
for(h = hash; h < hash + size; h++) {
printf("【地址】%d\t", h - hash);
Print(h);
}/*next*/
printf("--------------------\n");
}/*end Display*/
/*主函数,程序入口*/
int main(void)
{
/*哈希表变量声明*/
struct THash * hash = 0, * h = 0;
int cmd = 0; /*命令*/
char word[10]; /*单词单词*/
/*生成50个单词用的哈希表*/
hash = CreateNames(szHASH, HASH_ROOT, COUNT);
for(;;) {
printf("哈希表展示:1-显示哈希表;2-检索单词;其他任意键退出:\n"); cmd = getch();
cmd -= '0';
switch(cmd) {
case 1: Display(hash, szHASH); break;
case 2:
printf("请输入要检索的单词:");
scanf("%s", word);
h = Lookup(hash, word, HASH_ROOT);
printf("【地址】%d\t", h - hash);
Print(h);
break;
default:
free(hash);
return 0;
}/*end case*/
}/*next*/
return 0;
}/*end main*/。