Java散列表以拉链法解决冲突问题(以电话簿为例)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Java散列表以拉链法解决冲突问题(以电话簿为例)
原理
哈希表的结构
哈希表⼜被称为数组链表。

当插⼊删除操作和取值操作都较频繁时,我们可以采⽤哈希表来作为集合的数据结构。

定义:哈希表(Hash table,也叫散列表),是根据关键码值(Key value)⽽直接进⾏访问的数据结构。

也就是说,它通过把关键码值映射到表中⼀个位置来访问记录,以加快查找的速度。

这个映射函数叫做散列函数,存放记录的数组叫做散列表。

⼤致结构如下
但是本例题未采⽤Java⾃带的hash集合
特点:
1.第⼀列是⼀个数组。

因此我们在查找每⼀个链表头结点位置所耗费的时间复杂度都是常数1;
2.每⼀⾏都是⼀个链表。

理论上,这个链表可以⽆限扩⼤。

实际上当然是不⾏的,我们可以设想两种极端情况。

⼀种是链表的长度远远⼤于头结点数组的长度,那么这时这个哈希表其实就相当于⼀个链表,它取值操作的时间复杂度还是接近n。

另⼀种情况就是链表的长度远远⼩于头结点数组的长度,那么这时这个哈希表其实就相当于⼀个数组,它插⼊和删除操作的时间复杂度还是接近n。

为了避免这两种极端情况的出现,我们引⼊了⼀个控制变量peakValue(当前哈希表的数据个数/数组长度)。

如果这个值超过了某⼀界限,我们就对当前的哈希表进⾏重构。

3.每⼀次存放和取出数据,都是先找到对应的⾏号(即头结点的位置),然后再去遍历该⾏链表中的各个数据。

哈希表的构建思路
基本思路:⾸先我们需要开辟⼀个连续的数组来储存每个头结点,这个数组的⼤⼩是固定的。

每当我们从⽂件中读取出⼀个电话簿,⾸先要将其封装成⼀个节点。

然后根据number计算出相应的code,这个code会定位到唯⼀的⼀个链表头。

最后再把数据放到这个链表⾥⾯。

源代码
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class worktest {
class Listnode {
String name;
String number;
Object key;
Listnode next;
Listnode() {};
Listnode(String name, String number) {
= name;
this.number = number;
}
Listnode(String name, String number, Listnode next) {
= name;
this.number = number;
this.next = next;
}
}
public void read_file(Listnode []node){
File file = new File("d://电话号码.txt");
if (!file.exists()){
System.out.println("该⽂件不存在");
System.exit(0);
}
try {
Scanner scanner = new Scanner(file);
while(scanner.hasNext()){
String name = scanner.next();
String number = scanner.next();
Listnode listnode = new Listnode(name,number);
listnode.next = null;
int i = (number.charAt(10)-'0')%10;//除10取余
// System.out.println(i);
if(node[i] == null){//简单拉链法存数据
node[i] = listnode;
}
else{
listnode.next = node[i].next;
node[i].next = listnode;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public void show(Listnode []node){//输出电话簿
Listnode listnode = new Listnode();
for (int i = 0; i < 10; i++) {
listnode = node[i];
while (listnode!=null){
System.out.println(+" "+listnode.number);
listnode = listnode.next;
}
}
}
public void search1(Listnode []node, String name){//根据姓名查找 Listnode listnode = new Listnode();
for (int i = 0; i < 10; i++) {
listnode = node[i];
while (listnode != null){
if (.equals(name)){
System.out.println(+" "+listnode.number); }
listnode = listnode.next;
}
}
}
public void search2(Listnode []node, String number){//根据电话查找 Listnode listnode = new Listnode();
for (int i = 0; i < 10; i++) {
listnode = node[i];
while (listnode != null){
if (listnode.number.equals(number)){
System.out.println(+" "+listnode.number); }
listnode = listnode.next;
}
}
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
worktest test = new worktest();
Listnode []node = new Listnode[10];//key%10
test.read_file(node);
// test.show(node);
while(true){
System.out.println("请选择查找⽅式:1.按姓名查找,2.按电话查找,(输出其他退出)");
int choice = in.nextInt();
if (choice == 1){
String name = in.next();
long startTime = System.currentTimeMillis();//计算查找所消耗的时间
test.search1(node,name);
long endTime = System.currentTimeMillis();
System.out.println("本次查找消耗时间为"+(endTime-startTime)+"微秒");
}
else if(choice == 2){
String number = in.next();
long startTime = System.currentTimeMillis();
test.search2(node,number);
long endTime = System.currentTimeMillis();
System.out.println("本次查找消耗时间为"+(endTime-startTime)+"微秒");
}
else
break;
}
}
}
⽂件截图
总结反思
1.把⼀个String字符串转化为int型整数有两种意思。

A.字符串本⾝是0-9的数值,我们把这个数值由字符串类型变为int类型。

B.每个字符都有相应的ASCII码,⽽字符串是由字符组成的,因此我们可以获取它对应的ASCII的值。

在这⾥我们要做的⾃然是第⼆种,⽽这个值我们就把它作为hashcode,通过这个值我们可以唯⼀找到每个键值key对应的头结点。

扩展
可通过次数计算出平均查找长度。

相关文档
最新文档