Map集合

Map集合

在这里插入图片描述

1、概念

集是一个集合,它可以快速地寻找现有的元素,但是要查看元素,就需要查看的元素的精确副本。这不是一种非常通用的查找方式。通常,我们知道某些键的信息,并想要查找与之相对应的元素。映射表(map)数据结构就是为此设计的。映射表用来存放键值对。如果提供了键就能查找到相应的值。例如,有一张关于员工信息的记录表,键为员工ID,值为Employee对象。

Java 类库为映射表提供了两种通用的实现:HashMap和TreeMap。这两个类都实现了Map接口。

public class App {
    public static void main(String[] args) {
        Map<String,String> Student = new HashMap<>();
     //   MyMap<String,String> Student = new MyHashMap<String,String>();
        Student.put("19041211910","张三");
        Student.put("19041211911","李四");
        Student.put("19041211912","王麻子");
        Student.put("19041211913","牛二");
        Student.put("19041211914","马五");    
  //      Student.put("19041211932","牛魔王");  

        System.out.println(Student.get("19041211910"));
        System.out.println(Student.get("19041211911"));

    }
}

在这里插入图片描述

数组:采用连续的存储单元来存放数据,对于指定的下标查找,时间复杂度为O(1),平均复杂度为O(n)。

链表:链表的新增,删除等操作时间复杂度为O(1),查找为O(n)

2、编写自己的Map(映射集合)

/**
 * 需求分析:一些方法
 * 1、V put(K key, V value);
 * 2、V getVlaue(K key);
 *
 * 内部接口:
 *    interface Entry<K,V>
 */

public interface MyMap<K,V> {
    V put(K key, V value);
    V getValue(K key);
    int size();
    
    interface Entry<K,V>{
        public K getKey();
        public V getValue();

    }
}

class MyHashMap<K,V>   {
    public static int DEFAULTLEN=16;//默认数组容量大小
    public int put(K key,V value){
        int index = key.hashCode();
        System.out.println(value+":"+index+" :"+hash(index));
        return index;
    }

    public int hash(int hc){
        int hash=hc%(DEFAULTLEN-1);
        return hash;
    }
}

3、使自己的Map集合实现真正的功能

/**
 * @param <K>
 * @param <V>
 * @Author JosephLee
 * 数据结构:数组+链表
 *          数组:里面存放的是Entry对象
 * 方法:
 *      int size()
 *      V get(K key)
 *      V put(K key, V value)
 *      int hash(Object key)
 *
 * 内部类中的方法
 *      K getKey()
 *		void put(K key,V value)
 */
public class MyHashMap<K,V> implements MyMap<K,V>  {
    Node<K,V> node = new Node<K,V>();
    public static int DEFAULTLEN=16;    //默认数组容量大小
    private Node<K,V>[] table=null;
    int size=0;

    public MyHashMap(int length){
        DEFAULTLEN=length;
        table = new Node[DEFAULTLEN];
    }

    public MyHashMap(){
        this(DEFAULTLEN);
    }
    @Override
    public V put(K key, V value) {
        int index = hash(key);
        Node<K,V>[] tab;
        int n;
        if((tab=table)==null||tab[index]==null){
            table[index]=addEntry(index,key,value,null);
            size++;
        }
        else{
            Node<K,V> p = table[index];
            table[index]=addEntry(index,key,value,p);
        }
        return table[index].value;
    }



    public Node addEntry(int h,Object k, Object v, Node next){
        return new Node(h,k,v,next);
    }

    @Override
    public V getValue(K key){
        return getNode(key);
    }

    private V getNode(K key){
        if(size==0){
            return null;
        }
        int index = hash(key);
        if(table[index]==null){
            return null;
        }
        Node<K,V> p;
        for(p=table[index]; p!=null;p=p.next){
           if(p.getKey().hashCode()==key.hashCode()){
               return p.value;
           }
        }
        return null;
    }


    @Override
    public int size() {
        return size;
    }

    public int hash(K key){
        int index= key.hashCode()%(DEFAULTLEN-1);
        return Math.abs(index);
    }

    class Node<K,V> implements MyMap.Entry<K,V>{
        private Node<K,V> next;
        private int hash;
        private K key;
        private V value;

        public Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public Node(){

        }

        @Override
        public K getKey() {
            return key;
        }

        @Override
        public V getValue() {
            return value;
        }

    }
}

3、HashMap的一些其他特性

1)扩容机制

首先我们需要了解一下,构造 hash 表时,如果不指明初始大小,默认大小为 16(即 Node 数组大小 16 ),如果 Node[]数组中的元素达到(填充比* Node.length )重新调整 HashMap 大小 变为原来 2 倍大小,需要注意的是,扩容很耗时。

其中默认的填充比为 0.75
在这里插入图片描述
2)底层数据构:

HashMap 是数组+链表+红黑树(JDK1.8 增加了红黑树部分)实现的,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。简单来讲:

首先有一个每个元素都是链表(可能表述不准确)的数组,当添加一个元素(key-value)时,就首先计算元素 key 的 hash 值,以此确定插入数组中的位置,但是可能存在同一 hash 值的元素已经被放在数组同一位置了,这时就添加到同一 hash 值的元素的后面(俗称 hash 冲突,链表结构出现的实际意义也就是为了解决 hash 冲突的问题),他们在数组的同一位置,但是形成了链表,同一各链表上的 Hash 值是相同的,所以说数组存放的是链表。而当链表长度太长时,链表就转换为红黑树,这样大大提高了查找的效率。

4、HashTable

和HashMap的区别:

HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap。

HashMap 实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆。

HashMap中key和value都允许为null。key为null的键值对永远都放在以table[0]为头结点的链表中。

HashMap把Hashtable的contains方法去掉了

Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中。

Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。

Hashtable中,key和value都不允许出现null值。但是如果在Hashtable中有类似put(null,null)的操作,编译同样可以通过,因为key和value都是Object类型,但运行时会抛出NullPointerException异常,这是JDK的规范规定的。

5、TreeMap的一些特性

TreeMap能够把它保存的记录根据键排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。

import java.util.*;

public class App {

    public static void main(String[] args) {
        Map<String,String> Student = new HashMap<>();
//        MyMap<String,String> Student = new MyHashMap<String,String>();
        Student.put("19041211910","张三");
        Student.put("19041211911","李四");
        Student.put("19041211912","王麻子");

        Iterator ite = Student.keySet().iterator();
        while(ite.hasNext()){
            Object key=ite.next();
            System.out.println("HashMap.get(key) is: "+key);
        }
        System.out.println("————————————————————————————————————");

        Map<String,String> Student2 = new Hashtable<>();
        Student2.put("19041211910","张三");
        Student2.put("19041211911","李四");
        Student2.put("19041211912","王麻子");


        Iterator ite2 = Student2.keySet().iterator();
        while(ite2.hasNext()){
            Object key=ite2.next();
            System.out.println("HasTable.get(key) is: "+key);
        }

        System.out.println("————————————————————————————————————");

        Map<String,String> Student3 = new TreeMap<>();
        Student3.put("19041211910","张三");
        Student3.put("19041211911","李四");
        Student3.put("19041211912","王麻子");


        Iterator ite3 = Student3.keySet().iterator();
        while(ite3.hasNext()){
            Object key=ite3.next();
            System.out.println("TreeMap.get(key) is: "+key);
        }

    }
}

	Student3.put("19041211910","张三");
	Student3.put("19041211911","李四");
        Student3.put("19041211912","王麻子");


        Iterator ite3 = Student3.keySet().iterator();
        while(ite3.hasNext()){
            Object key=ite3.next();
            System.out.println("TreeMap.get(key) is: "+key);
        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值