• 23-哈希表


    1. 概述

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

    2. 案例

    有一个公司,当有新的员工来报道时,要求将该员工的信息(id, 性别, 年龄, 住址) 加入,当输入该员工的 id 时,要求查找到该员工的所有信息。要求: ① 不使用数据库,尽量节省内存,速度越快越好;② 添加时,保证按照 id 从低到高插入。

    2.1 思路分析

    2.2 代码实现

    public class HashTabDemo {
        public static void main(String[] args) {
            HashTab hashTab = new HashTab(7);
            for (int i = 0; i < 10; i++) {
                int num = (int) (Math.random()*1101);
                hashTab.add(new Emp(num, "emp_"+num));
            }
            hashTab.list();
            hashTab.add(new Emp(1, "emp_1"));
            hashTab.add(new Emp(1, "emp_1"));
            hashTab.add(new Emp(9999, "emp_9999"));
            hashTab.findEmpById(1);
            hashTab.deleteEmpById(1024);
            hashTab.add(new Emp(9999, "emp_9999"));
            hashTab.list();
        }
    }
    
    class HashTab {
        private EmpLinkedList[] empLinkedListArr;
        private int size; // 数组大小(链表条数)
    
        public HashTab(int size) {
            super();
            this.size = size;
            this.empLinkedListArr = new EmpLinkedList[size];
            // 上一行仅仅是创建了数组本身, 或者说只是创建了 size 个存放对象引用的空间(其值均为 null)
            // 要初始化这些引用, 让他们分别指向具体的 EmpLinkedList 对象才行
            for (int i = 0; i < size; i++)
                empLinkedListArr[i] = new EmpLinkedList();
        }
    
        // 散列函数 (取模法)
        public int hashFunc(int id) {
            return id % size;
        }
    
        // 添加雇员
        public void add(Emp emp) {
            // 1. 根据员工id, 先得到该员工应加入 [哪一条链表/数组哪个索引] 下
            int empLinkedListNo = hashFunc(emp.id);
            // 2. 将emp添加到对应的链表中
            empLinkedListArr[empLinkedListNo].add(emp);
        }
    
        // 根据 id 查找雇员
        public void findEmpById(int id) {
            Emp emp =  empLinkedListArr[hashFunc(id)].findEmpById(id);
            if (emp != null) System.out.println(emp);
            else System.out.println("没有找到该雇员");
        }
    
        public void deleteEmpById(int id) {
            Emp delEmp = empLinkedListArr[hashFunc(id)].deleteEmpById(id);
            if (delEmp != null) System.out.println(delEmp + "删除成功!");
            else System.out.println("删除失败!");
        }
    
        // 遍历所有的链表
        public void list() {
            for (int i = 0; i<size; i++) {
                System.out.printf("empLinkedListArr[%d]: ", i);
                empLinkedListArr[i].list();
            }
            System.out.println("---------------------------------------------------");
        }
    }
    
    class EmpLinkedList {
        // 首结点(不是头结点!)
        public Emp head;
    
        // 添加雇员
        public void add(Emp emp) {
            if (head == null) { // 是该链表的第 1 个结点
                head = emp;
            } else { // 不是第1个
                if (emp.id < head.id) {
                    emp.next = head;
                    head = emp;
                } else if (emp.id == head.id) {
                    System.out.println("id已存在, 添加失败!");
                    return;
                } else {
                    Emp curEmp = head;
                    while (curEmp.next != null) {
                        if (curEmp.next.id > emp.id) {
                            break;
                        } else if (curEmp.next.id == emp.id) {
                            System.out.println("id 已存在, 添加失败!");
                            return;
                        }
                        curEmp = curEmp.next;
                    }
                    emp.next = curEmp.next;
                    curEmp.next = emp;
                }
            }
        }
    
        // 根据 id 查找雇员
        public Emp findEmpById(int id) {
            // 判断链表是否为空
            if (head == null) return null;
    
            Emp curEmp = head;
            while (curEmp != null) {
                if (curEmp.id == id)
                    return curEmp;
                curEmp = curEmp.next;
            }
            // 到这了的话说明链表里没这 id 对应的雇员
            return null;
        }
    
        public Emp deleteEmpById(int id) {
            // 判断链表是否为空
            if (head == null) return null;
    
            Emp delEmp = null;
            if (head.id == id) { // 待删雇员恰为首结点
                delEmp = head;
                head = head.next;
                return delEmp; // !null → 找到了
            } else { // 非首结点
                Emp curEmp = head;
                while (curEmp.next != null) {
                    if (curEmp.next.id == id) {
                        delEmp = curEmp.next;
                        curEmp.next = delEmp.next;
                        return delEmp; // !null → 找到了
                    }
                    curEmp = curEmp.next;
                }
                return delEmp; // null → 未找到拥有该 id 的雇员
            }
        }
    
        // 遍历链表的雇员信息
        public void list() {
            if (head == null) {
                System.out.println("该链表为空");
                return;
            } else {
                Emp curEmp = head;
                while (curEmp != null) {
                    System.out.print(curEmp + " → ");
                    curEmp = curEmp.next;
                }
                System.out.println();
            }
        }
    }
    
    class Emp {
        public int id;
        public String name;
        public Emp next;
    
        public Emp(int id, String name) {
            super();
            this.id = id;
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "[id=" + id + ", name=" + name + "]";
        }
    }
    

    2.3 数组细节

  • 相关阅读:
    postgresql字符串函数
    ruby中的设计模式--策略模式
    (转)MySQL 性能优化的最佳20多条经验分享
    (转)ruby中的设计模式--模板方法
    观察者模式的应用
    postgresql的ARRAY_TO_STRING
    ruby和javascript的观察者模式
    mysql表连接的时候注意事项
    checkbox记忆功能的实现
    order by的注意事项
  • 原文地址:https://www.cnblogs.com/liujiaqi1101/p/12327846.html
Copyright © 2020-2023  润新知