当前位置: 首页 > news >正文

数据结构第18节 散列表 - 应用

散列表(Hash Table),也被称为哈希表,是一种数据结构,它通过使用哈希函数将键映射到数组的某个位置来实现快速查找。散列表通常提供平均时间复杂度为O(1)的查找、插入和删除操作,这使得它们在处理大量数据时非常高效。

基本概念

  • 哈希函数:一个将键转换为数组索引的函数。理想情况下,这个函数应该均匀地分布键,以避免冲突。
  • 冲突:当两个或多个不同的键被哈希函数映射到同一个数组索引时,就发生了冲突。解决冲突的方法包括开放寻址法和链地址法。
  • 负载因子:是散列表中元素的数量与散列表大小的比例。当负载因子过高时,散列表可能需要重新调整大小(扩容)以减少冲突。

Java中的散列表实现

在Java中,散列表可以通过HashMap类实现,它是Java集合框架的一部分。HashMap允许我们存储键值对,并且提供了快速的查找、插入和删除操作。

示例代码

假设我们要创建一个简单的散列表,用于存储学生ID和他们的成绩。以下是一个使用HashMap的示例:

import java.util.HashMap;public class StudentScores {public static void main(String[] args) {HashMap<Integer, Integer> scores = new HashMap<>();// 插入数据scores.put(101, 90);scores.put(102, 85);scores.put(103, 95);// 查找数据System.out.println("Score of student 101: " + scores.get(101));// 更新数据scores.put(101, 92);System.out.println("Updated score of student 101: " + scores.get(101));// 删除数据scores.remove(102);System.out.println("After removing student 102: " + scores);// 检查是否包含键System.out.println("Does the map contain student 101? " + scores.containsKey(101));}
}

在这个例子中,HashMap<Integer, Integer>表示散列表的键类型是整数,值类型也是整数。我们使用put方法插入数据,get方法查找数据,remove方法删除数据,以及containsKey方法检查散列表是否包含特定的键。

散列表的内部工作原理

HashMap的内部使用一个数组来存储键值对,每个位置上可以是一个链表或者红黑树(当链表长度达到一定阈值时)。当向HashMap中添加元素时,它会计算键的哈希码,然后使用该哈希码确定元素在数组中的位置。如果发生冲突,即多个键的哈希码指向同一位置,那么这些键值对会被链接在一起形成一个链表或红黑树。

当从HashMap中查找元素时,同样的哈希计算过程被用来定位元素。如果存在冲突,则遍历链表或红黑树直到找到正确的元素。

总结

散列表通过哈希函数和解决冲突的策略来实现高效的键值存储和检索。在Java中,HashMap是实现这一功能的常用工具。理解其内部工作原理有助于更有效地使用它并优化应用程序的性能。

让我们通过另一个案例来深入理解散列表(哈希表)的应用。这次我们将创建一个简单的图书管理系统,使用散列表来存储和管理图书馆中的书籍信息。

案例:图书管理系统

在这个案例中,我们将使用HashMap来存储图书的ISBN(国际标准书号)作为键,以及每本书的详细信息作为值。图书的详细信息可以用一个自定义的Book类来表示,其中包含书名、作者和出版年份等属性。

创建Book

首先,我们需要创建一个Book类,用于存储图书的详细信息。

public class Book {private String title;private String author;private int publicationYear;public Book(String title, String author, int publicationYear) {this.title = title;this.author = author;this.publicationYear = publicationYear;}@Overridepublic String toString() {return "Book{" +"title='" + title + '\'' +", author='" + author + '\'' +", publicationYear=" + publicationYear +'}';}
}
使用HashMap创建图书管理系统

接下来,我们使用HashMap<String, Book>来创建图书管理系统。我们将ISBN作为键,因为它是图书的唯一标识符。

import java.util.HashMap;public class LibrarySystem {private HashMap<String, Book> books;public LibrarySystem() {this.books = new HashMap<>();}public void addBook(String isbn, String title, String author, int publicationYear) {Book book = new Book(title, author, publicationYear);books.put(isbn, book);}public Book getBook(String isbn) {return books.get(isbn);}public void removeBook(String isbn) {books.remove(isbn);}public boolean containsBook(String isbn) {return books.containsKey(isbn);}
}
测试图书管理系统

现在我们可以创建一个LibrarySystem实例,并测试添加、获取和删除图书的功能。

public class Main {public static void main(String[] args) {LibrarySystem library = new LibrarySystem();// 添加图书library.addBook("978-0-306-40615-7", "The C Programming Language", "Brian W. Kernighan", 1978);library.addBook("978-0-201-63361-0", "Clean Code: A Handbook of Agile Software Craftsmanship", "Robert C. Martin", 2008);// 获取图书信息Book book = library.getBook("978-0-306-40615-7");System.out.println(book); // 输出: Book{title='The C Programming Language', author='Brian W. Kernighan', publicationYear=1978}// 检查图书是否存在System.out.println(library.containsBook("978-0-201-63361-0")); // 输出: true// 删除图书library.removeBook("978-0-201-63361-0");System.out.println(library.containsBook("978-0-201-63361-0")); // 输出: false}
}

在这个案例中,我们利用散列表的快速查找特性来高效地管理图书馆中的图书信息。由于ISBN是唯一的,因此使用它作为散列表的键可以确保没有重复的条目,同时也简化了查找和删除操作。

通过这个案例,你可以看到散列表在实际应用中如何提高数据访问效率,尤其是在处理具有唯一标识符的大数据集时。

好的,让我们继续扩展案例,这次我们将构建一个更复杂的场景——一个任务管理器,它能够帮助用户跟踪个人的任务清单。我们将使用散列表来存储任务,以便于快速查找和管理。

案例:任务管理器

定义Task

首先,我们需要定义一个Task类来存储任务的信息,比如任务的名称、描述、优先级和截止日期。

import java.time.LocalDate;public class Task {private String name;private String description;private int priority;private LocalDate dueDate;public Task(String name, String description, int priority, LocalDate dueDate) {this.name = name;this.description = description;this.priority = priority;this.dueDate = dueDate;}public String getName() {return name;}public String getDescription() {return description;}public int getPriority() {return priority;}public LocalDate getDueDate() {return dueDate;}@Overridepublic String toString() {return "Task{" +"name='" + name + '\'' +", description='" + description + '\'' +", priority=" + priority +", dueDate=" + dueDate +'}';}
}
创建任务管理器

接下来,我们创建一个TaskManager类,使用HashMap来存储任务。我们将使用任务的名称作为键,因为任务的名称应该是唯一的,以避免混淆。

import java.util.HashMap;public class TaskManager {private HashMap<String, Task> tasks;public TaskManager() {this.tasks = new HashMap<>();}public void addTask(Task task) {tasks.put(task.getName(), task);}public Task getTask(String name) {return tasks.get(name);}public void removeTask(String name) {tasks.remove(name);}public boolean containsTask(String name) {return tasks.containsKey(name);}
}
测试任务管理器

现在,我们可以创建一个TaskManager实例,并测试添加、获取和删除任务的功能。

import java.time.LocalDate;public class Main {public static void main(String[] args) {TaskManager manager = new TaskManager();// 添加任务manager.addTask(new Task("Buy groceries", "Milk, bread, eggs", 2, LocalDate.of(2024, 7, 12)));manager.addTask(new Task("Write report", "Finish Q2 sales report", 1, LocalDate.of(2024, 7, 15)));// 获取任务Task task = manager.getTask("Write report");System.out.println(task); // 输出: Task{name='Write report', description='Finish Q2 sales report', priority=1, dueDate=2024-07-15}// 检查任务是否存在System.out.println(manager.containsTask("Buy groceries")); // 输出: true// 删除任务manager.removeTask("Buy groceries");System.out.println(manager.containsTask("Buy groceries")); // 输出: false}
}

扩展功能:按优先级排序

为了使任务管理器更加实用,我们可以添加一个功能来按优先级对任务进行排序。虽然HashMap不保证顺序,但我们可以在TaskManager类中添加一个方法,使用优先级对任务进行排序并返回一个新的List

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;public class TaskManager {// ...public List<Task> getTasksSortedByPriority() {List<Task> sortedTasks = new ArrayList<>(tasks.values());Collections.sort(sortedTasks, Comparator.comparingInt(Task::getPriority));return sortedTasks;}
}

然后,在Main类中,我们可以调用getTasksSortedByPriority方法来获取按优先级排序的任务列表。

// 在Main类中
List<Task> sortedTasks = manager.getTasksSortedByPriority();
sortedTasks.forEach(System.out::println);

通过这些扩展,我们不仅能够有效地存储和管理任务,还能根据优先级对它们进行排序,从而帮助用户更好地组织和规划他们的工作。这个案例展示了散列表如何与其他数据结构如列表结合使用,以满足更复杂的需求。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 羊大师:暑期不“胖”秘籍:羊奶滋养,细嚼慢咽是关键!
  • 品牌策划学习资源全攻略:从入门到精通的推荐清单!
  • echarts 中国地图json文件
  • 神经网络构成、优化、常用函数+激活函数
  • 项目/代码规范与Apifox介绍使用
  • 孟德尔随机化--痛风与饮食
  • k8s 中间件
  • ProFuzzBench入门教学——使用(Ubuntu22.04)
  • Java使用POI导出后数字类型为常规类型,不能计算
  • 使用Mplayer实现MP3功能
  • 前端调用有道翻译
  • FPGA设计之跨时钟域(CDC)设计篇(1)----亚稳态到底是什么?
  • 牛市中途深度调整,一览下半场值得关注的 Solana 生态五大潜力项目
  • arm环境安装达梦数据库
  • Linux之免费证书工具certbot安装和使用
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • 【EOS】Cleos基础
  • classpath对获取配置文件的影响
  • CSS3 变换
  • DataBase in Android
  • FineReport中如何实现自动滚屏效果
  • java取消线程实例
  • js递归,无限分级树形折叠菜单
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • SQLServer之创建显式事务
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • 闭包--闭包之tab栏切换(四)
  • 编写符合Python风格的对象
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 看域名解析域名安全对SEO的影响
  • 前端_面试
  • 前端工程化(Gulp、Webpack)-webpack
  • 浅谈Golang中select的用法
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 使用parted解决大于2T的磁盘分区
  • 微信开源mars源码分析1—上层samples分析
  • - 转 Ext2.0 form使用实例
  • gunicorn工作原理
  • Java总结 - String - 这篇请使劲喷我
  • Prometheus VS InfluxDB
  • 新年再起“裁员潮”,“钢铁侠”马斯克要一举裁掉SpaceX 600余名员工 ...
  • ​VRRP 虚拟路由冗余协议(华为)
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • ‌U盘闪一下就没了?‌如何有效恢复数据
  • #《AI中文版》V3 第 1 章 概述
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (1)svelte 教程:hello world
  • (10)STL算法之搜索(二) 二分查找
  • (51单片机)第五章-A/D和D/A工作原理-A/D
  • (C语言)共用体union的用法举例
  • (Note)C++中的继承方式
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (附源码)springboot 个人网页的网站 毕业设计031623