【数据结构】---哈希表查找算法

 1、哈希查找也叫散列查找,整个散列查找过程大概分两步

      (1)在存储时通过散列函数计算记录的散列地址,并按此散列地址存储该记录。

      (2)当查找时,一样通过散列函数计算记录的散列地址,然后访问散列地址的记录。

    散列函数的构造方法

       (1)直接定址法

                      取关键字的某个线性函数值为散列地址

                           f(key) = a \times key +b

                   需要事先知道关键字的分布情况,适合查找表较小且连续的情况。

       (2)数字分析法

                       使用关键字的一部分来计算散列存储的位置。

                       适合处理关键字位数较大的情况。

       (3)平方取中法

               假设关键字是1234,那它的平方就是1522756,再抽取中间的3位就是277

               适合不知道关键字的分布,而位数又不是很大的情况。

       (4)折叠法

               将关键字从左到右分割成位数相等的几个部分,然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址。比如关键字是9876543210,散列表表长为三位,我们将它分成四组,987|654|321|0,然后将他们叠加求和等于1962,再求后三位得到散列地址962。

               适合事先不知道关键字的分布,关键字位数叫多的情况。

       (5)除留余数法   

                 此方法为最常用的构造散列函数的方法。

                 f(key) = key \ mod \ p

    处理冲突散列的方法

        (1)开放定址法

             开放定址法就是一旦出现了冲突,就去寻找下一个空的散列地址,只要散列地址够大,空的散列地址总会被找到。

                         f_{i}^{ }(key) = (f(key)+d_{i}^{ })\ MOD\ m \ (d{_{i}}^{ }=1,2,3,.....m-1)

        (2)再散列函数法

              事先准备多几个散列函数

                  f_{i}^{ } = RH_{i}^{ }(key) \ (i = 1,2,...k) 

               这里的RH_{i}^{ }就是不同的散列函数

        (3)链地址法

               将所有同关键字的记录存储在一个单链表中,称这种表为同义词子表,在散列表中只存储所有同义词子表的头指针。

2、散列表查找算法实现

     (1)首先定义一个散列表结构

     (2)对散列表进行初始化

     (3)对散列表进行插入操作

     (4)根据不同的情况选择散列函数和处理冲突的方法(这里选用的是除留余数法和开放定址法)

#include "stdio.h"    
#include "stdlib.h"   

#define HASHSIZE 10 // 定义散列表长度 
#define NULLKEY -32768 

typedef struct
{
	int *elem; // 数据元素存储地址,动态分配数组 
	int count; //  当前数据元素个数 
}HashTable;

int m = 0; 
		  
int Init(HashTable *H)
{
	int i;

	m = HASHSIZE;
	H->elem = (int *)malloc(m * sizeof(int)); //分配内存
	H->count = m;
	for (i = 0; i<m; i++)
	{
		H->elem[i] = NULLKEY;
	}
	return 1;
}


int Hash(int k)
{
	return k % m;//除留余数法
}


void Insert(HashTable *H, int k)
{
	int addr = Hash(k); 					 
	while (H->elem[addr] != NULLKEY)
	{
		addr = (addr+1) % m;//开放定址法
	}
	H->elem[addr] = k;
}

int Search(HashTable *H, int k)
{
	int addr = Hash(k); //求哈希地址

							
	while (H->elem[addr] != k)//开放定址法解决冲突
	{
		addr = (addr+1) % m;

		if (H->elem[addr] == NULLKEY || addr == Hash(k))
			return -1;
	}
	return addr;
}

void Result(HashTable *H)//散列表元素显示
{
	int i;
	for (i = 0; i<H->count; i++)
	{
		printf("%d ", H->elem[i]);
	}
	printf("\n");
}

void main()
{
	int i, j, addr;
	HashTable H;
	int arr[HASHSIZE] = { NULL };

	Init(&H);

	printf("输入关键字集合:");
	for (i = 0; i<HASHSIZE; i++)
	{
		scanf_s("%d", &arr[i]);
		Insert(&H, arr[i]);
	}
	Result(&H);

	printf("输入需要查找的元素:");
	scanf_s("%d", &j);
	addr = Search(&H, j);
	if (addr == -1)
		printf("元素不存在\n");
	else
		printf("%d元素在表中的位置是:%d\n", j,addr);

}

猜你喜欢

转载自blog.csdn.net/weixin_40567229/article/details/81137993