有序的Map集合

Posted 普通网友

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有序的Map集合相关的知识,希望对你有一定的参考价值。

我们通常使用的Map集合是HashMap,在大多数情况下HashMap可以满足我们的要求,但是HashMap有一个缺点:HashMap****是无序的,即其迭代顺序与其key或value的大小无关。而在某些情况下,如果我们需要Map集合里的元素有序,那么HashMap是不能满足我们的要求的。

那么有没有有序的Map集合呢?有,Java提供了两种有序的Map集合:LinkedHashMap和TreeMap;

**(一)**LinkedHashMap

LinkedHashMap继承了HashMap,是HashMap的子类。

其实LinkedHashMap与HashMap区别不大,也是通过计算键的hash值,映射到hash表中,那么LinkedHashMap是如何实现有序的呢?

LinkedHashMap不仅维护着一个hash****表,而且还维护着一个双向链表,而这个双向链表里的元素就是有序的。

LinkedHashMap的Entry继承于HashMap的Entry,并且增加了before和after属性。

可以看到before和after的类型都是Entry,LinkedHashMap通过before和after来构建双向链表。

LinkedHashMap的内部结构如图所示:

LinkedHashMap有两种排序方式:插入排序和访问排序(修改或访问一个元素后,将该元素移到队列末尾),默认是插入排序。使用accessOrder来标记使用哪种排序方式,accessOrder==true****时,表示使用访问排序默认为false;注意:LinkedHashMap的有序不是keyvalue的自然顺序

LinkedHashMap的插入:

put**():**

LinkedHashMap的put方法和HashMap的相同,不过LinkedHashMap重写了newNode方法,在插入时,会判断双向链表是否为空,如果为空,则将该Entry作为头结点head,否则在双向链表末尾插入该Entry;如果更新值(key相同),则会判断accessOrder是否为true,如果为true,则将该Entry移到双向队列的尾部。

get**():**

LinkedHashMap在get的时候,会判断accessOrder是否为true,即是否按访问顺序排序,如果是true,则会把该Entry移到双向队列的尾部。然后再返回value。

LinkedHashMap****的迭代:

LinkedHashMapIterator实现了迭代器的功能,其是对双向循环链表的遍历操作。但是这个迭代器是abstract的,不能直接被对象所用。

LinkedHashMap中的LinkedKeyIterator**,LinkedValueIteratorLinkedEntryIterator都继承了LinkedHashMapIterator,并且实现了Iterator接口,我们可以使用上面三种迭代器来迭代keyvalueentry。**三种迭代器迭代的是同一个双向链表,即迭代的元素是相同的,只是返回的类型不同。

遍历TreeMap的键值对

LinkedHashMap map = new LinkedHashMap();
Integer integ = null;
Iterator iter = map.entrySet().iterator();
while(iter.hasNext()) 
    Map.Entry entry = (Map.Entry)iter.next();
    // 获取key
    key = (String)entry.getKey();
        // 获取value
    integ = (Integer)entry.getValue();

**(二)**TreeMap

TreeMap也是一个有序的Map集合,其底层是一颗红黑树,该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

TreeMap的Entry结构如下:

可以看出来TreeMap的Entry其实是一个树节点,构建了一颗红黑树。而entry的插入,就是在红黑树中新增一个节点,并调整红黑树。

TreeMap****的插入:

put**():**

如果Comparator 为空,会使用key进行比较,按照从小到大的次序插入到红黑树中。

如果Comparator 不为空,则根据Comparator来进行比较。

TreeMap****的迭代:

PrivateEntryIterator实现了迭代器的功能,其是对红黑树进行遍历,返回的是红黑树中的有序序列。但是这个迭代器是abstract的,不能直接被对象所用。迭代时使用的是EntryIterator,ValueIterator,KeyIterator等迭代器。

除了顺序遍历,TreeMap还可以逆序遍历,由于TreeMap中的元素是从小到大的顺序排列的。因此,顺序遍历,就是从第一个元素开始,逐个向后遍历;而倒序遍历则恰恰相反,它是从最后一个元素开始,逐个往前遍历。

遍历TreeMap的键值对

TreeMap map = new TreeMap ();
Integer integ = null;
Iterator iter = map.entrySet().iterator();
while(iter.hasNext()) 
    Map.Entry entry = (Map.Entry)iter.next();
    // 获取key
    key = (String)entry.getKey();
        // 获取value
    integ = (Integer)entry.getValue();

Map集合以及Collections集合工具类

一、Collection集合主要特点与Map集合的区别

Collection:

单列集合;有两个子接口 List集合元素是有序的,可以重复的 Set集合元素是无序的,不可以重复

List:元素可重复,有序

ArrayList:底层数据结构是数组,查询快,增删慢,不同步,线程不安全,效率高;没有特殊说明一般使用ArrayList集合;

Vector:底层数据结构是数组,查询快,增删慢,同步,线程安全,效率低;有一个elements()特有迭代方法;

LinkedList:底层数据结构是链表,查询慢,增删快,不同步,线程不安全,效率高;有特有的增删方法;

Set:元素不可重复,无序

HashSet:底层数据结构是哈希表,由hashCode()和equals()方法支持它的不可重复性,且不保证迭代顺序,特别是不保证其顺序永久不变;

LinkedHashSet:继承HashSet 底层数据结构是哈希变和链表,所有是有序的,但是不可重复;

TreeSet:底层数据结构是红黑树数据结构(基于HashMap),保证元素唯一并且对其排序;

两种排序方式: 1、自然排序,需要元素所在的类实现Comparable接口,重写compareTo()方法;

2、选择器排序,创建TreeSet方法时需要创建Comparator接口的子实现类作为参数,并且重写其compare()方法。

Map:

双列集合;有两个主要子实现类 HashMap和TreeMap;Map集合是一种键值对的一种映射关系 key-value 其键唯一,值可重复

二、Map<K,V>接口

1、概述:public interface Map<K,V>将键映射到值的对象;一个映射不能包含重复的键;每个键最多只能映射到一个值。

K - 此映射所维护的键的类型

V - 映射值的类型

2、Map集合主要方法:

添加功能:

  V put(K key,V value):添加元素,如果键是第一次存储的时候,返回值null,如果键已经存在,再次存储的时候将第一次的值返回,并且后面的值覆盖掉前面的值

删除功能:

void clear()从此映射中移除所有映射关系(强拆)

V remove(Object key):删除键,返回值

判断功能:

boolean containsKey(Object key):判断当前Map集合中是否存在key:键

boolean containsValue(Object value):判断当前Map姐中是否存在value:值

获取功能:

Set<Map.Entry<K,V>> entrySet()返回一个键值对对象

V get(Object key)返回指定键所映射的值

Set<K> keySet():获取所有的键的集合

Collection<V> values():获取所有的值的集合

3、集合遍历:

A:方式一:使用keySet()方法,获取所有的键,再用键去获取所对应的值

HashMap<K,V> hm = new HashMap<K,V>();

//添加元素put(key,value)

Set<K> hs = hm.keySet();

for(K key : hs){

System.out.println(key + "---" + hm.get(key));

}

B:方式二:使用entrySet()方法,获取键值对对象,通过Map.Entry<K,Y>接口的getKey()、getValue()方法遍历集合

HashMap<K,V> hm = new HashMap<K,V>();

//添加元素put(key,value)

Set<Entry<K, Y>> s = hm.entrySet();

for(Entry<K, Y> se : s){

K key = se.getKey();

Y value = se.getValue();

system.out.println(key + "---" + value);

}

4、子实现类——HashMap

1)概述:HashMap集合是哈希表组成,并且他们的键允许null,值也可以允许null,,该类不能保证被元素的顺序恒久不变。

2)因为键的唯一性,所以在键的位置上存储自定义类的时候需要重写hashCode()和equals()方法;

值可以重复,不影响。

3)HashMap和Hashtable的区别

HashMap和Hashtable都实现了Map接口,他两是平级关系,Hashtable类似HashMap;

HashMap集合:允许有null键和null值,线程不安全,不同步,执行效率高;

Hashtable集合:不允许有null键和null,线程安全的,同步,效率低。

3)LinkedHashMap——extends HashMap

底层是有哈希表和链表组成,可以保证键的唯一性,和有序性(存取一致);

5、子实现类——TreeMap

1)底层基于红黑树的数据结构,该映射根据其键的自然顺序进行排序,或者根据其键进行选择器排序,具体取决于使用的构造方法

2)排序方式:(排序排的都是键,排序方式同TreeSet)

自然排序:要求储存在键位置上的元素的类implements Comparable接口并且重写compareTo()方法;

选择器排序:使用TreeMap(Comparator<T> comparator)构造器,使用匿名内部类的方式创建Comparator的子实现类对象,并重写compare()方法;

三、Collections —— 集合工具类

1、概述:对集合操作的工具类,没有构造方法,所有方法都由static修饰,可以直接调用;

2、常用方法:

public static <T> void sort(List<T> list):默认自然排序:将集合中的元素升序排序

默认的自然排序:需要元素所在的类implements Comparable接口,重写compareTo()方法,指定排序的方式;

比较器排序:public static <T> void sort(List<T> list,Comparator<T> c)

注意,如果两种排序方式都是使用了,那么最终结果遵从比较器排序。

public static <T> int binarySearch(List> list,T key):二分查找搜索法:key:查找的元素

public static void reverse(List list):反转功能(StringBuffer也有reverse功能)

public static void shuffle(List<?> list):随机置换,打乱顺序

四、集合嵌套遍历

1、ArrayList嵌套HashMap

/*需求:

假设ArrayList集合的元素是HashMap。有3个。

每一个HashMap集合的键和值都是字符串。

元素我已经完成,请遍历。

结果:

周瑜---小乔

吕布---貂蝉


郭靖---黄蓉

杨过---小龙女


令狐冲---任盈盈

林平之---岳灵珊*/

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Set;

public class ArratListTest {

public static void main(String[] args) {

ArrayList<HashMap<String,String>> al = new ArrayList<HashMap<String,String>>();

HashMap<String,String> hm1 = new HashMap<String, String>();

HashMap<String,String> hm2 = new HashMap<String, String>();

HashMap<String,String> hm3 = new HashMap<String, String>();

hm1.put("周瑜", "小乔");

hm1.put("吕布", "貂蝉");

hm2.put("郭靖", "黄蓉");

hm2.put("杨过", "小龙女");

hm3.put("令狐冲", "任盈盈");

hm3.put("林平之", "岳灵珊");

al.add(hm1);

al.add(hm2);

al.add(hm3);

for(HashMap<String,String> hm : al){

Set<String> keySet = hm.keySet();

for(String key : keySet){

System.out.println(key + "---" + hm.get(key));

}

System.out.println();

}

}

}

2、HashMap嵌套ArrayList

/*需求:

假设HashMap集合的元素是ArrayList。有3个。

每一个ArrayList集合的值是字符串。

元素我已经完成,请遍历。

结果:

三国演义

吕布

周瑜

笑傲江湖

令狐冲

林平之

神雕侠侣

郭靖

杨过 */

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Set;


public class HsahMapTest {

public static void main(String[] args) {

HashMap<String,ArrayList<String>> hm = new HashMap<String,ArrayList<String>>();

ArrayList<String> al1 = new ArrayList<String>();

al1.add("吕布");

al1.add("周瑜");

ArrayList<String> al2 = new ArrayList<String>();

al2.add("令狐冲");

al2.add("林平之");

ArrayList<String> al3 = new ArrayList<String>();

al3.add("郭靖");

al3.add("杨过");

hm.put("三国演义", al1);

hm.put("笑傲江湖", al2);

hm.put("神雕侠侣", al3);

Set<String> keySet = hm.keySet();

for(String key : keySet){

System.out.println(key);

ArrayList<String> valueList = hm.get(key);

for(String value : valueList){

System.out.println("\t" + value);

}

}

}

}

3、HashMap嵌套HashMap

/*HashMap嵌套HashMap

  基础班

  陈玉楼 20

  高跃 22

  就业班

  李杰 21

  曹石磊 23

先存储元素,然后遍历元素*/

import java.util.HashMap;

import java.util.Set;

public class HsahMapTest2 {

public static void main(String[] args) {

HashMap<String,HashMap<String,Integer>> hm = new HashMap<String,HashMap<String,Integer>>();

HashMap<String,Integer> hm1 = new HashMap<String, Integer>();

hm1.put("陈玉楼", 20);

hm1.put("高跃", 22);

HashMap<String,Integer> hm2 = new HashMap<String, Integer>();

hm2.put("李杰", 21);

hm2.put("曹石磊", 23);

hm.put("基础班", hm1);

hm.put("就业班", hm2);

Set<String> keySet = hm.keySet();

for(String key : keySet){

System.out.println(key);

HashMap<String, Integer> hashMap = hm.get(key);

Set<String> keySet2 = hashMap.keySet();

for(String key2 : keySet2){

System.out.println("\t" + key2 + "\t" + hashMap.get(key2));

}

}

}

}


以上是关于有序的Map集合的主要内容,如果未能解决你的问题,请参考以下文章

Java集合中List和 Map区别?

Java集合类 List Set Map

颗粒归仓--java集合

JAVA的集合类型都有哪些

07.集合和泛型

java基础 Map集合