数据结构思维 第九章 `Map`接口
第九章 Map
接口
原文:Chapter 9 The Map interface
译者:飞龙
协议:CC BY-NC-SA 4.0
自豪地采用谷歌翻译
在接下来的几个练习中,我介绍了Map
接口的几个实现。其中一个基于哈希表,这可以说是所发明的最神奇的数据结构。另一个是类似的TreeMap
,不是很神奇,但它有附加功能,它可以按顺序迭代元素。
你将有机会实现这些数据结构,然后我们将分析其性能。
但是在我们可以解释哈希表之前,我们将从一个Map
开始,它使用键值对的List
来简单实现。
9.1 实现MyLinearMap
像往常一样,我提供启动代码,你将填写缺少的方法。这是MyLinearMap
类定义的起始:
public class MyLinearMap<K, V> implements Map<K, V> {private List<Entry> entries = new ArrayList<Entry>();
该类使用两个类型参数,K
是键的类型,V
是值的类型。MyLinearMap
实现Map
,这意味着它必须提供Map
接口中的方法。
MyLinearMap
对象具有单个实例变量,entries
,这是一个Entry
的ArrayList
对象。每个Entry
都包含一个键值对。这里是定义:
public class Entry implements Map.Entry<K, V> {private K key;private V value;public Entry(K key, V value) {this.key = key;this.value = value;}@Overridepublic K getKey() {return key;}@Overridepublic V getValue() {return value;}}
Entry
没有什么,只是一个键和一个值的容器。该定义内嵌在MyLinearList
中,因此它使用相同类型的参数,K
和V
。
这就是你做这个练习所需的所有东西,所以让我们开始吧。
9.2 练习 7
在本书的仓库中,你将找到此练习的源文件:
MyLinearMap.java
包含练习的第一部分的起始代码。MyLinearMapTest.java
包含MyLinearMap
的单元测试。
你还会找到 Ant 构建文件build.xml
。
运行ant build
来编译源文件。然后运行ant MyLinearMapTest
;几个测试应该失败,因为你有一些任务要做。
首先,填写findEntry
的主体。这是一个辅助方法,不是Map
接口的一部分,但是一旦你让它工作,你可以在几种方法中使用它。给定一个目标键(Key),它应该搜索条目(Entry)并返回包含目标的条目(按照键,而不是值),或者如果不存在则返回null
。请注意,我提供了equals
,正确比较两个键并处理null
。
你可以再次运行ant MyLinearMapTest
,但即使你的findEntry
是正确的,测试也不会通过,因为put
不完整。
填充put
。你应该阅读Map.put
的文档,http://thinkdast.com/listput ,以便你知道应该做什么。你可能希望从一个版本开始,其中put
始终添加新条目,并且不会修改现有条目;这样你可以先测试简单的情况。或者如果你更加自信,你可以一次写出整个东西。
一旦你put
正常工作,测试containsKey
应该通过。
阅读Map.get
的文档,http://thinkdast.com/listget ,然后填充方法。再次运行测试。
最后,阅读Map.remove
的文档,http://thinkdast.com/maprem 并填充方法。
到了这里,所有的测试都应该通过。恭喜!
9.3 分析MyLinearMap
这一节中,我展示了上一个练习的答案,并分析核心方法的性能。这里是findEntry
和equals
。
private Entry findEntry(Object target) {for (Entry entry: entries) {if (equals(target, entry.getKey())) {return entry;}}return null;
}private boolean equals(Object target, Object obj) {if (target == null) {return obj == null;}return target.equals(obj);
}
equals
的运行时间可能取决于target
键和键的大小 ,但通常不取决于条目的数量,n
。那么equals
是常数时间。
在findEntry
中,我们可能会很幸运,并在一开始就找到我们要找的键,但是我们不能指望它。一般来说,我们要搜索的条目数量与n
成正比,所以findEntry
是线性的。
大部分的MyLinearMap
核心方法使用findEntry
,包括put
,get
,和remove
。这就是他们的样子:
public V put(K key, V value) {Entry entry = findEntry(key);if (entry == null) {entries.add(new Entry(key, value));return null;} else {V oldValue = entry.getValue();entry.setValue(value);return oldValue;}
}
public V get(Object key) {Entry entry = findEntry(key);if (entry == null) {return null;}return entry.getValue();
}
public V remove(Object key) {Entry entry = findEntry(key);if (entry == null) {return null;} else {V value = entry.getValue();entries.remove(entry);return value;}
}
put
调用findEntry
之后,其他一切都是常数时间。记住这个entries
是一个ArrayList
,所以降魔为添加元素平均是常数时间。如果键已经在映射中,我们不需要添加条目,但我们必须调用entry.getValue
和entry.setValue
,而这些都是常数时间。把它们放在一起,put
是线性的。
同样,get
也是线性的。
remove
稍微复杂一些,因为entries.remove
可能需要从一开始或中间删除ArrayList
的一个元素,并且需要线性时间。但是没关系:两个线性运算仍然是线性的。
总而言之,核心方法都是线性的,这就是为什么我们将这个实现称为MyLinearMap
(嗒嗒!)。
如果我们知道输入的数量很少,这个实现可能会很好,但是我们可以做得更好。实际上,Map
所有的核心方法都是常数时间的实现。当你第一次听到这个消息时,可能似乎觉得不可能。实际上我们所说的是,你可以在常数时间内大海捞针,不管海有多大。这是魔法。
我们不是将条目存储在一个大的List
中,而是把它们分解成许多短的列表。对于每个键,我们将使用哈希码(在下一节中进行说明)来确定要使用的列表。
使用大量的简短列表比仅仅使用一个更快,但正如我将解释的,它不会改变增长级别;核心功能仍然是线性的。但还有一个技巧:如果我们增加列表的数量来限制每个列表的条目数,就会得到一个恒定时间的映射。你会在下一个练习中看到细节,但是首先要了解哈希!
在下一章中,我将介绍一种解决方案,分析Map
核心方法的性能,并引入更有效的实现。
数据结构思维 第九章 `Map`接口相关推荐
- 数据结构思维 第一章 接口
第一章 接口 原文:Chapter 1 Interfaces 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 本书展示了三个话题: 数据结构:从 Java 集合框架(JCF)中的 ...
- 操作系统--第九章 操作系统接口--习题答案
操作系统第四版课后的全部习题答案,学习通作业答案. 说明:操作系统其他章节的习题答案也在此"操作系统"专栏. 第九章 1.系统安全的复杂性表现在哪几个方面? 答:(1)多面性:大规 ...
- Java编程思想读书笔记——第九章:接口
第九章 接口 接口和实现类 抽象类是介于普通的类和接口之间的中庸之道,抽象类也是一种重要的工具,你不可能总是使用纯接口 9.1 抽象类和抽象方法 抽象方法声明的语法: abstract void f( ...
- 严蔚敏数据结构习题第九章
l第九章查找作业题目9.9 9.14 9.19 9.25 9.31 9.33,平台提交入口已开通,截止日期6月20日 https://www.cnblogs.com/kangjianwei101/p/ ...
- 数据结构思维 第二章 算法分析
第二章 算法分析 原文:Chapter 2 Analysis of Algorithms 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 我们在前面的章节中看到,Java 提供了 ...
- 【操作系统】第九章-操作系统接口
九.操作系统接口 前言 操作系统作为计算机系统资源的管理者,对系统中的所有硬件和软件资源进行统一的管理和操纵.无论是用户(程序)或OS的外层软件,凡是涉及到系统资源的有关操作,都必须作为服务请求提交给 ...
- 汤晓丹的第四版计算机操作系统--第九章总结概述
第九章 操作系统接口 管道命令:人们又进一步把重定向思想加以扩充,用符号"|"来连接两条命令,使其前一条命令的输出作为后一条命令的输入. 在计算机系统中设置了两种状态:系统态(或称 ...
- 数据结构思维 第十一章 `HashMap`
第十一章 HashMap 原文:Chapter 11 HashMap 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 上一章中,我们写了一个使用哈希的Map接口的实现.我们期望这 ...
- 【JAVA SE】第九章 接口
第九章 接口 文章目录 第九章 接口 一.概念 二.接口与类 1.相似点 2.区别 三.接口特性 四.接口的声明 五.接口的实现 六.接口的继承 七.接口的多继承 八.标记接口 一.概念 接口(Int ...
最新文章
- CentOS下挂载硬盘(fdisk,mkfs.ext4,mount)
- android webview拍照,在android 2.2/2.3中使用webview从camera中照相并且上传的实现
- Spring中注解注入bean和配置文件注入bean
- Java 面向对象:构造器详解
- 【C语言】大程序(.c和.h)头文件和源文件
- ​突破 1nm!台积电祭出“半金属”取代硅材料;搜狗发布手语 AI 合成主播;iOS 微信 8.0.6 版本更新|极客头条...
- 求方程式ax2 bx c=0的根c语言,关于求方程ax2+bx+c=0根的问题
- 谈谈javascript中原型继承
- Urllib库的基本使用
- 给定一个邻接矩阵,求可达矩阵及强连通、单向连通、弱连通、不连通的判断
- 关于PopWindow的一些介绍
- 设圆半径r=1.5,圆柱高h=3,求圆周长、圆面积、圆球表面积、圆球体积、圆柱体积用scanf输人数据,输出计算结
- busybox linux使用教程,使用BusyBox制作Linux根文件系统
- java语言基础 一张纸的厚度0.08mm,求对折对次之后能达到珠穆朗玛峰的高度(8844)用(循环求while)
- Oracle如何根据一个日期计算同比环比的日期
- Canvas如何等待所有图片加载完成才开始绘图
- qrious二维码生成插件
- ios模拟器 - Simulator录制视频
- css溢出影藏然后显示三个小点
- 数学建模方法总结(matlab)
热门文章
- android 图片剪切组件,Android 图片裁剪库 uCrop
- python实现特定软件代理_Python针对特定服务定制的代理工具V2.0------(proxyHandler.py)...
- java实现浏览器ui中的收藏夹_谷歌改进Google Chrome浏览器中的PDF浏览器 带来全新UI...
- 使用NRF2401 STM32F303ZET6 NUCLEO 开发板
- winsocket(1)
- 12025.petalinux 之phy调试ping(三)
- 单片机中volatile的应用
- python爬虫爬取图片代码_python爬虫实战 爬取天极图片
- linux input子系统分析--子系统核心.事件处理层.事件传递过程
- 【JAVA SE】第一章 Java语言概述、环境变量和HelloWorld