hashtable

发布时间 2023-12-01 17:17:27作者: MGLblog

哈希表

一、基本介绍

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

二、应用实例

有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址…),当输入该员工的 id 时,要求查找到该员工的所有信息。

要求:
(使用哈希表)。添加时,保证按照 id 从低到高插入
1)使用链表来实现哈希表,该链表不带表头[ 即,链表的第一个节点存放雇员信息 ]
2)思路分析:

  • hashtable存放是含有链表LinkedList的数组,而每个数组元素是一个链表,链表是员工结点

3)代码实现增删查改

//创建Hashtable 管理多条链表
class Hashtable_ {
    private int maxSize;
    private EmpLinkedList[] empLinkedListArray;

    public Hashtable_(int maxSize) {
        this.maxSize = maxSize;
        empLinkedListArray = new EmpLinkedList[maxSize];
//        因为这是一个对象数组,上面那一行只是创建了数组,就相当于一个二维数组,
//        不去new每个对象的话,导致每个对象元素EmpLinkedList为null,导致null指针异常
        for (int i = 0; i < maxSize; i++) {
            empLinkedListArray[i] = new EmpLinkedList();
        }
    }

    //    添加员工
    public void add(Emp emp) {
//        根据员工id,得到该员工应当添加到哪条链表
        int empLinkedListNO = hashFun(emp.id);
        //将emp添加到对应的链表中
        empLinkedListArray[empLinkedListNO].add(emp);

    }

    //    编写散列函数,使用一个简单取模法
    public int hashFun(int id) {
        return id % maxSize;
    }

    //    遍历hashtable
    public void list() {
        for (int i = 0; i < maxSize; i++) {
            empLinkedListArray[i].list(i);
        }
    }

    //    查找
    public void findEmpById(int id) {
//        使用散列函数确定到哪一条链表查找
        int empLinkedListNO = hashFun(id);
        Emp emp = empLinkedListArray[empLinkedListNO].findEmpById(id);
        if (emp != null) {
            System.out.printf("在第%d条链表中找到员工id =%d\n", (empLinkedListNO + 1), id);
        } else
            System.out.println("没有找到该员工");
    }

    //    删除指定id的员工
    public void delete(int id) {
        //        使用散列函数确定到哪一条链表查找
        int empLinkedListNO = hashFun(id);
        empLinkedListArray[empLinkedListNO].delete(id);

    }
}

//员工
class Emp {
    public int id;
    public String name;
    public Emp next;

    public Emp(int id, String name) {
        this.id = id;
        this.name = name;
        this.next = null;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

//链表
class EmpLinkedList {
    //    头指针,执行第一个Emp,因此我们这个链表的head是直接指向第一个Emp
    private Emp head;//默认null

    //    添加雇员到链表
    public void add(Emp emp) {
        if (head == null) {
            head = emp;
            return;
        }
        Emp curEmp = head;//辅助指针,帮助定位到最后
        while (true) {
            if (curEmp.next == null)
                break;
            curEmp = curEmp.next;
        }
        curEmp.next = emp;
    }

    //    遍历
    public void list(int no) {
        if (head == null) {
            System.out.println("第 " + (no + 1) + " 链表为空~~");
            return;
        }
        Emp curEmp = head;
        while (curEmp != null) {
            System.out.printf("=> id=%d name=%s\t", curEmp.id, curEmp.name);
            curEmp = curEmp.next;
        }
        System.out.println();
    }

    //    根据id查找员工
//    如果查找到,就返回emp,否则返回null
    public Emp findEmpById(int id) {
        if (head == null) {
            System.out.println("链表为空");
            return null;
        }
        Emp curEmp = head;
        while (true) {
            if (curEmp.id == id)
                break;//找到了
            if (curEmp.next == null) {//没有该员工
                curEmp = null;
                break;
            }
            curEmp = curEmp.next;
        }
        return curEmp;
    }

    //    删除指定id的员工
    public void delete(int id) {
        if (head == null) {
            System.out.println("链表为空~~");
            return;
        }
        Emp curEmp = head;
        while (true) {
            //        删除头节点
            if (head.id == id) {
                head = head.next;
                return;
            }
            if (curEmp.next == null)
                break;
            if (curEmp.next.id == id) {
                curEmp.next = curEmp.next.next;
                return;
            } else
                System.out.println("找不到需要删除的员工");
            curEmp = curEmp.next;
        }
    }

}

三、测试

public static void main(String[] args) {
    Hashtable_ hashtable_ = new Hashtable_(7);
    String key = "";
    Scanner scanner = new Scanner(System.in);
    while (true) {
        System.out.println("add:  添加员工");
        System.out.println("list:  显示员工");
        System.out.println("find:  查找员工");
        System.out.println("delete:  删除员工");
        System.out.println("exit:  退出系统");
        key = scanner.next();
        switch (key) {
            case "add":
                System.out.println("请输入id:");
                int id = scanner.nextInt();
                System.out.println("请输入名字:");
                String name = scanner.next();
                Emp emp = new Emp(id, name);
                hashtable_.add(emp);
                break;
            case "list":
                hashtable_.list();
                break;
            case "find":
                System.out.println("请输入你要查找的id:");
                id = scanner.nextInt();
                hashtable_.findEmpById(id);
                break;
            case "delete":
                System.out.println("请输入要删除的id:");
                id = scanner.nextInt();
                hashtable_.delete(id);
                break;
            case "exit":
                scanner.close();
                System.exit(0);
            default:
                System.out.println("您的输入有误,请重新输入!!!");
                break;
        }
    }

}