散列表(Hash table)

散列表Hash table,也叫哈希表),是根据关键码(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

一、基本概念

l散列函数(Hash function):若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f为散列函数,按这个思想建立的表为散列表。

l冲突:对不同的关键字可能得到同一散列地址,即key1key2,而f(key1)=f(key2),这种现象称冲突。具有相同函数值的关键字对该散列函数来说称做同义词。

l均匀散列函数:若对于关键字集合中的任一个关键字,经散列函数映象到地址集合中任何一个地址的概率是相等的,则称此类散列函数为均匀散列函数(Uniform Hash function),这就是使关键字经过散列函数得到一个“随机的地址”,从而减少冲突。

综上所述,根据散列函数H(key)和处理冲突的方法将一组关键字映象到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“象”作为记录在表中的存储位置,这种表便称为散列表,这一映象过程称为散列造表或散列,所得的存储位置称散列地址。

二、构造散列函数的方法

l直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=keyH(key) = akey + b,其中ab为常数(这种散列函数叫做自身函数);

l数字分析法:找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址;

l平方取中法: 取关键字平方后的中间几位作为散列地址;

l折叠法:将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(去除进位)作为散列地址;

l随机数法: 选择一个随机函数,取关键字的随机函数值为它的散列地址,即h(key)=random(key),其中random为伪随机函数,但要保证函数值是在0m-1之间;

l除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p, p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词。

三、处理冲突的方法

l开放寻址法Hi=(H(key) + di) MOD m, i=1,2,, k(k<=m-1),其中H(key)为散列函数,m为散列表长,di为增量序列,可有下列三种取法:

      1.di=1,2,3,, m-1,称线性探测再散列;

      2.di=1^2, (-1)^2, 2^2,(-2)^2, (3)^2, , ±(k)^2,(k<=m/2)称二次探测再散列;

      3.di=伪随机数序列,称伪随机探测再散列。

l再散列法Hi=RHi(key), i=1,2,,k. RHi均是不同的散列函数,即在同义词产生地址冲突时计算另一个散列函数地址,直到冲突不再发生,这种方法不易产生“聚集”,但增加了计算时间;

l链地址法(拉链法):将所有关键字为同义词的记录存储在同一线性链表中;

l建立一个公共溢出区

四、查找性能分析

在哈希表上进行查找的过程和哈希造表的过程是一致的。一些关键码可通过散列函数转换的地址直接找到,而另一些关键码在散列函数得到的地址上产生了冲突,需要按处理冲突的方法进行查找。查找过程中,关键码的比较次数,取决于产生冲突的多少,影响产生冲突多少有以下三个因素:

      1.   散列函数是否均匀;

      2.   处理冲突的方法;

      3.   散列表的装填因子α= 填入表中的元素个数 / 散列表的长度

α是散列表装满程度的标志因子。散列表的平均查找长度是装填因子α的函数,只是不同处理冲突的方法有不同的函数。

五、散列表java实现(MyHashtable

 下面是散列表的一个简单实现,采用开放寻址法线性探测解决冲突,参考《数据结构Java语言描》,Micheal Main著。

 

public class MyHashtable {
	
	private int manyItems;//表中元素个数
	private Object[] keys;
	private Object[] data;
	private boolean[] hasBeenUsed;//若索引i处存在元素,则hasBeenUsed[i]为ture,否则为false
	
	public MyHashtable(int capacity) {
		if(capacity <= 0)
			throw new IllegalArgumentException("capacity is negative");
		
		keys = new Object[capacity];
		data = new Object[capacity];
		hasBeenUsed = new boolean[capacity];
	}
	
	//hash函数
	private int hash(Object key) {
		return Math.abs(key.hashCode()%data.length);
	}
	
	//当前索引发生冲突,找下一索引
	private int nextIndex(int i) {
		if(i + 1 == data.length) {
			return 0;
		} else {
			return i + 1;
		}
	}
	
	//如果在表中找到指定的关键字,返回值为关键字的索引,否则返回-1
	private int findIndex(Object key) {
		int count = 0;
		int i = hash(key);
		
		while((count < data.length) && hasBeenUsed[i]) {
			if(key.equals(keys[i])) {
				return i;
			} else {
				count++;
				i = nextIndex(i);
			}
		}
		return -1;
	}
	
	public Object get(Object key) {
		int index = findIndex(key);
		
		if(index == -1) {
			return null;
		} else {
			return data[index];
		}
	}
	
	public Object put(Object key, Object element) {
		int index = findIndex(key);
		Object answer;
		
		if(index != -1) {
			answer = data[index];
			data[index] = element;
			return answer;
		} else if(manyItems < data.length) {
			index = hash(key);
			while(keys[index] != null) {
				index = nextIndex(index);
			}
			keys[index] = key;
			data[index] = element;
			hasBeenUsed[index] = true;
			manyItems++;
			return null;
		} else {
			throw new IllegalStateException("Hashtable is full!");
		}
	}
	
	public Object remove(Object key) {
		int index = findIndex(key);
		Object answer = null;
		
		if(index != -1) {
			answer = data[index];
			data[index] = null;
			keys[index] = null;
			manyItems--;
		}
		return answer;
	}
	
	public boolean contains (Object key) {
		return (findIndex(key) != -1);
	}
	
	public static void main(String[] args) {
		MyHashtable table = new MyHashtable(100);
		
		table.put(1, "china");
		table.put(2, "美国");
		System.out.println(table.get(2).toString());
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值