哈希查找

本文详细介绍了哈希法的思想及其构造方法,包括数字分析法、平方取中法、分段叠加法和除留余数法。同时,阐述了在构造哈希函数过程中可能出现的冲突问题,并提出了开放定址法、再哈希法和链地址法三种解决冲突的方法。通过Java代码实例展示了如何运用除留余数法和开放地址法进行哈希查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

哈希法的思想实际上就是建立一种映射,一种建立在元素关键字k与元素存储位置p之间的映射H,使得p = H(k) , 此函数称之为哈希函数。

构造哈希函数方法有很多:

数字分析法:

         从关键字中选出分布较为均匀的若干位,构成哈希地址,但是此种情况一般适用于能预先知道关键字集合,并且每个关键字的位数比哈希表的地址码位数多时

平方取中法:

         以关键字的平方值的中间几位作为存储地址,这适用于关键字中的每一位都有某些数字重复出现频度很高的现象

分段叠加法:

         将关键字分为位数相等的及部分,然后将这几部分相加,再舍弃最高进位后的结果当作哈希地址。这适用于关键字的数字位数特别多的情况

除留余数法:

         假设哈希表长为m,p为不大于m的素数,则哈希函数为:H(k) = k %p。

伪随机数法:

        采用一个伪随机数作为哈希函数:H(K) = random(K);这适用于关键字长度不等,分布不均的情况。


在构造哈希函数的过程中,难免会发生以下情况:

有待散列元素(18,75,60,42,54) 取p=7,用除留余数法进行构造时:  H(18) = 18 %7 = 4   ;  H(75)= 75%7 = 5 ; H(60) = 60%7 = 4 ......

这样,元素18和60的哈希地址就产生冲突了,为了解决这个问题,通常有三种办法:

开放定址法:

      即当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1 ,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2……直到找出一个不冲突的哈希地址pi,将相应元素存入其中。

再哈希法:

       构造若干个哈希函数,当发生冲突时,根据另一个哈希函数计算下一个哈希地址,直到冲突不再发生。即:Hi=Rhi(key)     i=1,2,……k,其中:Rhi——不同的哈希函数,这种方法不易产生聚集,但增加了计算时间。

链地址法:

       将所有哈希地址相同的关键字都存储在同一链表中。

以下是运用除留余数法和开放地址法进行哈希查找的JAVA代码:

import java.util.Arrays;
import java.util.Random;

public class HashSearch {
	static int m; // 哈希表长
	static int hashTable[]; // 哈希表

	public static void main(String[] args) {
		int a[] = new int[100000];
		for (int i = 0; i < a.length; i++) {
			a[i] = i * 2;
		}// 初始化数组,数组中全是偶数
		int key = new Random(System.currentTimeMillis()).nextInt(200000);
		// 随机产生要查找的关键字
		for (int i = a.length;; i++) {
			if (isSushu(i)) {
				m = i;
				break;
			}
		}// 根据数组大小确定哈希表长
		hashTable = new int[m];
		Arrays.fill(hashTable, -1);// 将哈希表全部初始化为-1
		System.out.println(key + "  " + hashSearch(a, key));
	}

	public static boolean hashSearch(int a[], int key) {// 哈希查找
		ConstructHash(a);// 根据数组构造出哈希表
		int position = key % m;
		if (hashTable[position] == -1) {
			return false;
		} else if (hashTable[position] == key) {
			return true;
		} else {// 用线性探测再散列解决冲突
			for (int i = 1; i < m; i++) {
				int pi = (position + i) % m;
				if (hashTable[pi] == -1) {
					return false;
				} else if (hashTable[pi] == key) {
					return true;
				}
			}
			return false;
		}
	}

	public static void ConstructHash(int a[]) {// 构造哈希表
		for (int i = 0; i < a.length; i++) {
			int pi = Hash(a[i]);
			if (hashTable[pi] == -1) {
				hashTable[pi] = a[i];
			} else {// 用线性探测再散列解决冲突
				for (int j = 1; j < m; j++) {
					int position = (pi + j) % m;
					if (hashTable[position] == -1) {
						hashTable[position] = a[i];
						j = m;//中断内循环
					}
				}
			}
		}
	}

	public static int Hash(int n) {// 除留余数法构造哈希函数
		return n % m;
	}

	public static boolean isSushu(int i) {// 将哈希表长定为素数
		int k = (int) Math.sqrt((double) i);
		for (int j = 2; i <= k; j++) {
			if (i % j == 0) {
				return false;
			}
		}
		return true;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值