开散列的简单模拟(一)

[color=red][b]1. 散列[/b][/color]

散列有两种形式。一种是开散列(或外部散列),它将字典元素存放在一个潜无穷的空间里,因此它能处理任意大小的集合。
另一种是闭散列(或内部散列), 它使用一个固定大小的存储空间,因此它能处理的集合的大小不能超过它的存储空间的大小。

[color=red][b]2. 开散列[/b][/color]

[b](1)下图是一个开散列表,它表示了开散列的基本数据结构。[/b]


[img]http://dl.iteye.com/upload/attachment/269635/ee6f6ef5-73d2-37d0-82f4-6be901975953.jpg[/img]

[b](2) 基本思想[/b]

[color=blue][b]开散列的基本思想是将集合的元素(可能有无穷多个)划分成有穷多个类。例如,划分为0、1、2、....、B-1这B个类。用散列函数h将集合中的每个元素x映射到0、1、2、....、B-1之一,h(x)的值就是x所属的类。h(x)称为x的散列值。上面所说的每一个类称为一个桶,并且称x属于桶h(x).

我们用一个链接表表示一个桶。x是将第i个链接表中的元素当且仅当h(x)=i,即x属于第i个桶。B个桶(链接表)的桶(表)头存放于桶(表)头数组中。[/b][/color]

用散列表来存储集合中的元素时,总希望将集合中的元素均匀地散列到每一个桶中,使得当集合中含有n个元素时,每个桶中平均有n/B个元素。如果我们能估计出n,并选择B与n差不多大小时,则每个桶中平均只有一两个元素。这样,字典的每个运算所需要的平均时间就是一个与n和B无关的小常数。由此可以看出,开散列表是将数组和链接表结合在一起的一种数据结构,并希望能利用它们各自的优点且克服它们各自的缺点。因此,[color=blue][b]如何选择随机的散列函数,使它能将集合中的元素均匀地散列到各个桶中是散列技术的一个关键。[/b][/color]

[b](3) 求余运算。[/b]

如果x是不是数值型,将字符串x中的每个字符转换成一个整数,然后将字符串每个字符所对应的整数相加,用和除以B的余数作为h(x)的值,显然这个余数是0、1、2、....、B-1之一。

[b]3. 模拟代码:[/b]

package boke.dictionary;
/**
* 开散列的简单模拟(一): 桶元素
*
* @since jdk1.6
* @author 毛正吉
* @version 1.0
* @date 2010.05.25
*
*/
public class Node {
public int iData;
public Node next;

public Node(int i) {
iData = i;
}
}

-----------------------------------------------

package boke.dictionary;

/**
* 开散列的简单模拟(一): 作为简单模拟,元素选取整型
*
* @since jdk1.6
* @author 毛正吉
* @version 1.0
* @date 2010.05.25
*
*/
public class Hash {

/**
* @param args
*/
public static void main(String[] args) {
Hash hh = new Hash(1000);
for (int i = 0; i <= 100; i++) {
hh.insert(i);
}
System.out.println(hh.find(10));
System.out.println(hh.find(50));
System.out.println(hh.find(90));
System.out.println(hh.find(1000));

hh.insert(1000);
System.out.println(hh.find(1000));

hh.delete(10);
System.out.println(hh.find(10));

hh.insert(0);
System.out.println(hh.find(0));

}

private Node[] bucket; // 桶
private int maxSize; // 桶的个数

/**
* 构造方法
*
* @param maxSize
*/
public Hash(int maxSize) {
this.maxSize = maxSize;
bucket = new Node[maxSize];
makeNULL();
}

/**
* 字典初始化
*/
public void makeNULL() {
for (int i = 0; i < maxSize - 1; i++) {
bucket[i] = null;
}
}

/**
* 查找x是否在字典中
*
* @param x
* @return
*/
public boolean find(int x) {
int mod = x % maxSize;
Node current = bucket[mod];

while (current != null) {
if (current.iData == x) {
return true;
} else {
current = current.next;
}
}

return false;
}

/**
* 插入x到hash字典中
*
* @param x
*/
public void insert(int x) {
if (!find(x)) {
Node node = new Node(x);
int mod = x % maxSize;

Node old = bucket[mod];
bucket[mod] = node;
bucket[mod].next = old;
} else {
System.out.println("该值已存在,不能重复插入!");
}
}

/**
* 从hash字典中删除x
*
* @param x
*/
public void delete(int x) {
int mod = x % maxSize;

if (bucket[mod] != null) {
if (bucket[mod].iData == x) {
bucket[mod] = bucket[mod].next;
} else {
Node current = bucket[mod];
while (current.next != null) {
if (current.next.iData == x) {
current.next = current.next.next;
} else {
current = current.next;
}
}
}
}
}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值