【数据结构】哈希表(散列表)

avatar
作者
筋斗云
阅读量:0
介绍

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

哈希表的实际应用

Java 程序操作数据最普通的方式是直接操作数据库,经过一番操作后数据库将结果返回给程序,但是这种结构对数据库的操作非常频繁,造成了不必要的开销。

为了解决这个问题,我们可以在程序与数据库之间添加一个缓存层,把常用的数据加载到缓存层,这样就可以在缓存层中取数据,避免了对数据库的操作。

在缓存层,我们可以使用一些常见的缓存产品,如 Redis 、Memcache 等,但是这些缓存产品太重量级了,我们也可以使用哈希表来自己写一个缓存层,即先把数据存入哈希表,使用时从哈希表中取出数据。

 我们可以使用 数组+链表 来实现一个哈希表,结构如下

使用哈希表管理雇员信息

public class HashTabDemo {     public static void main(String[] args) {         //创建一个哈希表         HashTab hashTab = new HashTab(7);         //写一个简单菜单         String key;         Scanner scanner = new Scanner(System.in);         while (true) {             System.out.println();             System.out.println("add:添加雇员");             System.out.println("list:显示雇员");             System.out.println("find:查找雇员");             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);                     hashTab.add(emp);                     break;                 case "list":                     hashTab.list();                     break;                 case "find":                     System.out.println("请输入要查找的id");                     id = scanner.nextInt();                     hashTab.findEmpById(id);                     break;                 case "exit":                     System.out.println("程序退出");                     scanner.close();                     System.exit(0);                 default:                     break;             }         }     } }  //表示一个雇员 class Emp {     public int id;     public String name;     public Emp next;  // next 默认为空      public Emp(int id, String name) {         super();         this.id = id;         this.name = name;     } }  //创建 EmpLinkedList ,表示链表 class EmpLinkedList {     //头指针,指向第一个 Emp ,因此我们这个链表的 head 是直接指向第一个 Emp     private Emp head;  //默认为空      //添加雇员到链表     /*     说明     1.假定当添加雇员时,id 是自增长的,即 id 的分配总是从小到大的     因此我们将该雇员直接加入本链表的最后即可      */     public void add(Emp emp) {         //如果是添加第一个雇员         if (head == null) {             head = emp;             return;         }         //如果不是添加第一个雇员,则使用一个辅助的指针,帮助定位到最后         Emp curEmp = head;         while (true) {             if (curEmp.next == null) {  //说明链表到最后                 break;             }             curEmp = curEmp.next;  //后移         }         //退出时直接将 emp 加入链表         curEmp.next = emp;     }      //遍历链表的雇员信息     public void list(int no) {         int tempNo = no + 1;         if (head == null) {  //说明链表为空             System.out.println("第" + tempNo + "条链表为空");             return;         }         System.out.print("第" + tempNo + "条链表的信息为:");         Emp curEmp = head;  //辅助指针         while (true) {             System.out.printf(" =>  id=%d name=%s\t", curEmp.id, curEmp.name);             if (curEmp.next == null) {                 break;             }             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;  //这时 curEmp 就指向查找的雇员             }             //退出             if (curEmp.next == null) {  //说明遍历当前链表没有找到该雇员                 curEmp = null;                 break;             }             curEmp = curEmp.next;  //以后         }         return curEmp;     } }  //创建 HashTab 管理多条链表 class HashTab {     private EmpLinkedList[] empLinkedListArray;     private int size;  //表示共有多少条链表      //构造器     public HashTab(int size) {         this.size = size;         //初始化 empLinkedListArray         empLinkedListArray = new EmpLinkedList[size];         //不要忘记分别初始化每个链表!!!         for (int i = 0; i < size; i++) {             empLinkedListArray[i] = new EmpLinkedList();         }     }      //编写一个散列函数,使用一个简单取模法     public int hashFun(int id) {         return id % size;     }      //添加雇员     public void add(Emp emp) {         //根据员工的 id ,得到该员工应该添加到哪条链表         int empLinkedListNO = hashFun(emp.id);         //将 emp 添加到对应的链表中         empLinkedListArray[empLinkedListNO].add(emp);     }      //遍历所有链表,遍历 HashTab     public void list() {         for (int i = 0; i < size; i++) {             empLinkedListArray[i].list(i);         }     }      //根据输入的 id 查找雇员     public void findEmpById(int id) {         //使用散列函数确定到哪条链表查找         int empLinkedListNO = hashFun(id);         Emp emp = empLinkedListArray[empLinkedListNO].findEmpById(id);         if (emp != null) {  //找到             System.out.printf("在第%d条链表中找到雇员id=%d", (empLinkedListNO + 1), id);         } else {             System.out.println("在哈希表中没有找到该雇员");         }     } }

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!