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

Posted high范式

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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) {
            this.name = name;
            this.number = number;
        }

        Listnode(String name, String number, Listnode next) {
            this.name = 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.name+" "+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 (listnode.name.equals(name)){
                    System.out.println(listnode.name+" "+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.name+" "+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对应的头结点。

扩展

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

以上是关于Java散列表以拉链法解决冲突问题(以电话簿为例)的主要内容,如果未能解决你的问题,请参考以下文章

哈希表(散列表)冲突解决方法

散列的基本概念散列函数的构造方法散列函数的冲突调节方法线性探查法和拉链法

散列表常见散列函数及处理冲突的方法

求开散列表的平均查找长度

JAVA_map总结

数据结构 散列表