散列表(一)

O(1)复杂度的实现

实现O(1)复杂度要求:

  1. 存储单元中存储的内容与存储地址是一一对应的
  2. 存储单元是可以随机读取的(任意顺序直接读取–数组)
public class CapableTest {
	private Object[] values=new Object[10];
	public void add(int item) {
		values[item]=item;
	}
	public void remove(int item) {
		values[item]=null;
	}
	public boolean contain(int item) {
		if(values[item]==null) {
			return false;
		}else {
			return true;
		}
	}
}

以上是一个简易的O(1)复杂度的容器。
我们不再把values[1]称作存储单元,操作系统中的存储单元为一个字节,而int为4个字节,我们把values[1],values[2]称作一个槽。

如果需要将20个数据放入10个槽中,将会发生数据碰撞。解决数据碰撞的办法可以用链接法,就是两个数据共用一个地址,但是在不同的链表节点。也就是将槽拓展为链表。

链接法处理碰撞

public class CapableTest2 {
	private Object[] values=new Object[10];
	
	private int H(int num) {
		if(num>0 && num<=9) {
			return num;
		}else {
			return num-10;
		}
	}
	
	
	public void add(int item) {
		if(values[H(item)]==null) {
			LinkedList<Integer> linkedList = new LinkedList<>();
			linkedList.add(item);
			values[H(item)]=linkedList;
		}else {
			@SuppressWarnings("unchecked")
			LinkedList<Integer> linkedList=(LinkedList<Integer>)values[H(item)];
			linkedList.add(item);
		}
	}
	
	public void remove(int item) {
		@SuppressWarnings("unchecked")
		LinkedList<Integer> linkedList=(LinkedList<Integer>) values[H(item)];
		linkedList.remove((int)item);
	}
	
	
	public boolean contain(int item) {
		if(values[H(item)]==null) {
			return false;
		}else {
			@SuppressWarnings("unchecked")
			LinkedList<Integer> linkedList=(LinkedList<Integer>) values[H(item)];
			return linkedList.contains(item);
		}
	}
}

这样就实现了一个槽存放多个元素

如何让21亿人使用10个地址?

好吧,有了链接法,我们有了足够的房子以应对可能发生的碰撞。但是我们仍然希望碰撞发生的几率越小越好,特别是当我们把数值范围由 0~19 扩大到 0~int.MaxValue 时候。有什么办法能把21亿个数值映射成10个数值,并且尽量减少碰撞?

除法散列法

h(k) = k mod m
其中,k为槽中的数值,m是数组的大小(为了简单起见本例中固定为10)。这样我们得到第一个正整数范围内通用的 IntSet

public class IntSet
{
    private object[] _values = new object[10];
 
    private int H(int value)
    {
        return value % 10;
    }
    // 其它部分与 之前 相同
}

再大的数除于10的余数都一定介于0-9之间。
其次让h(k)得出1的数值为1,11,21,31…等。碰撞的K值比较分散(我们想要尽量减少碰撞)
需要注意的是 m 不应是 2 的幂即 2p 的形式,此时 h(k) 将等于 k 的二进制的最低 p 位。以 m = 23和k=170为例
h(k) = 170 mod 23 = (27+ 25 + 23 + 22 + 21 ) mod 23 = 21>
也就是说只有最低的 p 位不能被 2p 整除。这有什么问题呢?问题是我们不想假设 k 的分布,所以通常希望 h(k) 的值依赖于 k 的所有位而不是最低 p 位。天知道 k 不会是“11010000、00110000、10010000……”

乘法散列法

h(k) = ⌊m(kA mod 1)⌋
其中,A 是一个大于0小于1的常数,例如可以取 A = 2654435769 / 232。kA mod 1 的意思是取 kA 的小数部分。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值