数据结构 —— HashMap1

在进行HashMap的学习之前先学习一下Map接口。

Java中数据存储方式最底层的两种结构,一种是数组,另一种就是链表。

  1. 数组的特点:连续空间,寻址迅速,但是在删除或者添加元素的时候需要有较大幅度的移动,所以查询速度快,增删较慢。
  2. 链表的特点:链表正好相反,由于空间不连续,寻址困难,增删元素只需修改指针,所以查询慢、增删快。

那么有没有一种数据结构来综合一下数组和链表,以便发挥他们各自的优势?答案是肯定的!就是:哈希表哈希表具有较快(常量级)的查询速度,及相对较快的增删速度, 所以很适合在海量数据的环境中使用。一般实现哈希表的方法采用“拉链法”,我们可以理解为“链表的数组”,

Map的实现

Map也是容器的一种,拥有自己独特的数据结构,Map的每一个元素叫做键值对。Map的底层实现基础是我们学过的数组和链表,因为Map的数据机构问题,Map中的各个元素之间没有连接的关系,所以通过数组的方式存储Map 的每个元素

Map内部实现了一个红黑树,该结构具有自动排序的功能,因此map内部的所有元素都是有序的。红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行这样的操作,故红黑树的效率决定了map的效率。

Map的 Key - Value

key和value之间存在单向一对一关系,即通过指定的key,总能找到唯一的、确定的value。从Map中取出数据时,只要给出指定的key,就可以取出对应的value。

如图:
在这里插入图片描述

Map的优缺点

  • 优点:内部实现了一个红黑树使得map的很多操作在很小的时间复杂度下就可以实现,因此效率很高
  • 缺点:空间占有率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外的保存父节点,孩子节点以及红/黑性质,使得每一个节点都需要占有大量的空间。

Map接口的主要实现类

在这里插入图片描述

  • AbstractMap : 实现了Map接口的抽象类。Map的基本实现,其他Map的实现类可以通过继承AbstractMap来减少编码量

  • SortedMap :继承Map。保证按照键的升序排列的映射,对entrySet、keySet和values方法返回的结果进行迭代时,顺序就会反映出来。

  • NavigableMap:继承SortedMap,含有返回特定条件最近匹配的导航方法。

  • HashMap:继承AbstractMap。Map接口基于哈希表的实现,是使用频率最高的用于键值对处理的数据类型。它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,特点是访问速度快,遍历顺序不确定,线程不安全,最多允许一个key为null,允许多个value为null。可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap类。

  • HashTable:继承了Dictionary类,实现了Map接口的抽象类。Hashtable和HashMap从存储结构和实现来讲有很多相似之处,不同的是它继承自Dictionary类,而且是线程安全的,另外Hashtable不允许key和value为null。并发性不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。Hashtable不建议在新代码中使用,不需要线程安全的场合可以使用HashMap,需要线程安全的场合可以使用ConcurrentHashMap。

  • LinkedHashMap: LinkedHashMap继承了HashMap,是Map接口的哈希表和链表实现。它维护着一个双重链表。此链表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。

  • TreeMap : Map接口基于红黑树的实现。能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺序),也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。不允许key值为空,非同步的;

Map的遍历

第一种:KeySet()
将Map中所有的键存入到set集合中。因为set具备迭代器。所有可以迭代方式取出所有的键,再根据get方法。获取每一个键对应的值。 keySet():迭代后只能通过get()取key 。
取到的结果会乱序
,是因为取得数据行主键的时候,使用了HashMap.keySet()方法,而这个方法返回的Set结果,里面的数据是乱序排放的。
典型用法如下:
Map map = new HashMap();
map.put(“key1”,“lisi1”);
map.put(“key2”,“lisi2”);
map.put(“key3”,“lisi3”);
map.put(“key4”,“lisi4”);
//先获取map集合的所有键的set集合,keyset()
Iterator it = map.keySet().iterator();
//获取迭代器
while(it.hasNext()){
Object key = it.next();
System.out.println(map.get(key));
}

第二种:entrySet()
Set<Map.Entry<K,V>> entrySet() //返回此映射中包含的映射关系的 Set 视图。(一个关系就是一个键-值对),就是把(key-value)作为一个整体一对一对地存放到Set集合当中的。Map.Entry表示映射关系。entrySet():迭代后可以e.getKey(),e.getValue()两种方法来取key和value。返回的是Entry接口。
典型用法如下:
Map map = new HashMap();
map.put(“key1”,“lisi1”);
map.put(“key2”,“lisi2”);
map.put(“key3”,“lisi3”);
map.put(“key4”,“lisi4”);
//将map集合中的映射关系取出,存入到set集合
Iterator it = map.entrySet().iterator();
while(it.hasNext()){
Entry e =(Entry) it.next();
System.out.println(“键”+e.getKey () + “的值为” + e.getValue());
}
推荐使用第二种方式,即entrySet()方法,效率较高。
对于keySet其实是遍历了2次,一次是转为iterator,一次就是从HashMap中取出key所对于的value。而entryset只是遍历了第一次,它把key和value都放到了entry中,所以快了。两种遍历的遍历时间相差还是很明显的。

第三种:Map.foreach()

如果是jdk8,使用Map.foreach()方法。
典型用法如下:
Map map = new HashMap();
map.put(“key1”,“lisi1”);
map.put(“key2”,“lisi2”);
map.put(“key3”,“lisi3”);
map.put(“key4”,“lisi4”);
map.forEach((k,v) -> {
System.out.println(k + “:” + v);
});

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值