java专题——散列表查找

概念:在记录的存储位置和它的关键字之间建立一个确定对应关系f,使得每个关键字key对应一个存储位置f(key)。

           这种对应关系称之为散列函数,又称哈希函数。散列技术将记录存储于一块连续存储空间中,这个连续存储空间            称之为散列表或哈希表。


常用构造方法——直接定址法、数字分析法、平方取中法、折叠法、残留余数法。


主要分析:残留余数法

f(key) = key mod p (p <= m)

mod是取模(取余)

p一般是取比m小,但最接近于m的质数(质数:能被自身或1除的数,如1、3、5、7...)

ex:对以下12个关键字以表长12取模分别放入相应的位置。

下标       0     1    2     3    4   5     6     7   8     9    10     11  
关键字   12   25  38  15  16  29   78  67  56   21   22    47


当然,通常情况会有冲突

如18、30、42,这些数最后都会与序号为6的冲突,18mod12=6  30mod12=6 42mod12=6


常用解决冲突的方法——开放定址法、再散列函数法、链地址法、公共溢出区法


主要分析:开放定址法(线性探测法)

fi(key) = ( f(key) + di ) mod m (di = 1,2,3,...,m-1)

如果遇到冲突,就继续将散列值与di相加,接着残留余数法散列。


                            二次探测法

fi(key) = ( f(key) + q ) mod m (di = 1^2,-1^2,2^2,-2^2,...,q^2,-q^2,q<=m/2)

此方法是为了不让散列值集中在某区域。


                   随机探测法

fi(key) = ( f(key) + di ) mod m (di为随机序列)




package 散列表;

import java.util.Random;



public class HashProcess {

	public static void main(String[] args) {
		int[] arr = new int[10];
		int[] hashTable = new int[arr.length*2+1];
		Random random = new Random();
		for(int i=0 ; i<arr.length ; i++){
			
			arr[i] = random.nextInt(10)%10+10;
		}
		for(int a : arr){
			InsertHash(hashTable,a);
			System.out.print(a + " ");
		}
		
		System.out.println(SearchHash(arr[6],hashTable.length,hashTable));
	
	}
	
	

	private static boolean SearchHash(int a,int len,int[] ht) {
		int addr = Hash(a,len);
		while(ht[addr] != a){
			addr = (addr+1)%len;
			if(ht[addr] == 0 || addr == Hash(a,len)){
				return false;
			}
		}
		return true;
	}



	private static void InsertHash(int[] hashTable, int a) {
		int len = hashTable.length;
		int addr = Hash(a,len);
	    while(hashTable[addr] != 0){
	    	addr = (addr+1)%len;
	    }
	    hashTable[addr] = a;
	}

	private static int Hash(int a,int len) {
		return a%len;	
	}

}


/* * 基于散列表实现的(无序)词典结构 * 采用分离链策略解决冲突 */ package dsa; public class Dictionary_HashTable implements Dictionary { private Dictionary[] A;//桶数组,每个桶本身也是一个(基于列表实现的)词典结构 private int N;//散列表长 private final double maxLemda = 0.75;//装填因子上限 private int size;//词典结构的规模 private EqualityTester T;//判等器 //默认构造方法 public Dictionary_HashTable() { this(0, new EqualityTesterDefault()); } //构造方法 public Dictionary_HashTable(int n, EqualityTester t) { T = t; N = p(n);//桶数组容量取为不小于n的最小素数 A = new Dictionary[N]; for (int i=0; i<N; i++) A[i] = new Dictionary_DLNode(T); size = 0; } /***************************** 辅助方法 *****************************/ //散列定址函数(采用模余法) private int h(Object key) { return key.hashCode() % N; } //判断n是否为素数 private static boolean prime(int n) { for (int i=3; i<1+Math.sqrt(n); i++) if (n/i*i == n) return false; return true; } //取不小于n的最小素数 private static int p(int n) { if (3>n) n = 3; n = n | 1;//奇数化 while (!prime(n)) n += 2; return n; } /***************************** ADT方法 *****************************/ //查询词典结构当前的规模 public int getSize() { return size; } //判断词典结构是否为空 public boolean isEmpty() { return 0==size; } //若词典中存在以key为关键码的条目,则返回其中的一个条目;否则,返回null public Entry find(Object key) { return A[h(key)].find(key); } //返回由关键码为key的条目组成的迭代器 public Iterator findAll(Object key) { return A[h(key)].findAll(key); } //插入条目(key, value),并返回该条目 public Entry insert(Object key, Object value) { Entry entry = A[h(key)].insert(key, value);//将新条目插至桶A[h(key)]对应的子词典 size ++;//更新规模记录 if (size > N * maxLemda) rehash();//若装填因子过大,则重散列 return entry;//返回null标志 } //若词典中存在以key为关键码的条目,则将其摘除并返回;否则,返回null public Entry remove(Object key) { Entry oldEntry = A[h(key)].remove(key); if (null!=oldEntry) size--; return oldEntry; } //返回词典中所有条目的一个迭代器 public Iterator entries() { List L = new List_DLNode(); for (int i=0; i<N; i++) { Iterator it = A[i].entries(); while (it.hasNext()) L.insertLast(it.getNext()); } return new IteratorElement(L); } //重散列 private void rehash() { Iterator it = this.entries(); N = p(N<<1); A = new Dictionary[N];//桶数组容量至少加倍 for (int i=0; i<N; i++) A[i] = new Dictionary_DLNode(T);//为每个桶分配一个子词典 while (it.hasNext()) {//将其对应的词典结构中的 Entry e = (Entry)it.getNext();//各条目逐一取出,将其 Object k = e.getKey();//关键码和 Object v = e.getValue();//数据对象 A[h(k)].insert(k, v);//整合为新的条目,插入对应的子词典中 } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值