草庐IT

手撕HashMap(二)

ciao'lynniyer 2023-04-05 原文
  • 这里再补充几个手撕HashMap的方法

1、remove()

  1. remove 方法参数值应该是键值对的键的值,当传入键值对的键的时候,remove 方法会删除对应的键值对
  2. 需要利用我们自己先前创建的 hashcodeList 来实现,hashcodeList 存入了所有被使用的 hashcode 值,方便后续的操作
  3. 在 put() 中,当添加新的键值对时,就会调用hashcodeList.add(hashcode);来存入添加的 hashcode 值
  4. hashcodeList:
    /**
     * 不需要遍历数组,大大减少了代码量,直接存入hashcode的值
     * 用来记录被使用的hashcode,方便后续其他方法的操作
     */
    List<Integer> hashcodeList = new ArrayList<>();
  1. remove() 方法的思路:
    • 根据传入的 key 的值,遍历 hashmap
    • 当 key 的值相同时,删除它,与此同时遍历 hashcodeList
    • 当 hashcodeList 中存储的哈希值与 key 通过 hashcode(key) 方法后得到的哈希值相等时,删除这个 hashcodeList 值
  2. 代码:
     /**
     * 删除传入的key值所对应的键值对对象
     *
     * @param key 传入的key
     */
    @Override
    public void remove(K key) {
        int hashcode = hashcode(key);
        for (Entry<K, V> entry : mapArr[hashcode]
        ) {
            //要把hashcodeList中的hashcode删除
            hashcodeList.removeIf(integer -> hashcode(entry.getKey()) == integer);
            //删除 mapArr 
            if (entry.getKey().equals(key)) {
                mapArr[hashcode].remove();
            }
        }
    }

2、clear()

  1. clear 方法调用之后,会清除 hashmap 中所有的关联或映射,即清除所有的 key、value
  2. 思路:
    • hashcodeList 中存储的是使用过的哈希值,而 mapArr 的下标是对应的哈希值,存储的是对应的value值
    • 遍历 hashcodeList,将里面的值一个个取出来并放到 mapArr 的下标,一一调用 remove 方法
    /**
     * 清除 HashMap 中的所有关联或者映射
     */
    @Override
    public void clear() {
        for (int i = 0; i < hashcodeList.size(); i++) {
            for (Entry<K, V> entry : mapArr[hashcodeList.get(i)]
            ) {
                mapArr[hashcodeList.get(i)].remove();
                //同时要把hashcodeList中的hashcode清除
                hashcodeList.clear();
            }
        }
    }

3、containsKey()

  1. 传入一个 key 的值,判断是否存在这个键所对应的键值对,存在则返回 true,不存在则返回 false
  2. 思路:
    • 先生成传入 key 的对应的哈希值
    • 判断下标为这个哈希值的数组是否为空,为空则直接返回 false
    • 如果不为空,则遍历这个数组找到相同的 key 则返回 true,否则返回 false
    • 会出现数组下标越界,如果出现,则说明不存在这个下标,自然也不存在这个哈希值,所以可以用 try、catch 环绕直接返回false
    /**
     * 判断是否存在key值所对应的映射,返回一个布尔值
     *
     * @param key 传入一个key的值
     * @return 判断是否存在key值所对应的映射,返回一个布尔值
     */
    @Override
    public boolean containsKey(K key) {
        int hashcode = hashcode(key);
        try {
            //如果发现没存过,直接返回false
            if (null == mapArr[hashcode]) {
                return false;
            } else {
                //如果遍历能查找到key,则返回true
                //如果遍历不能找到,则返回null
                for (Entry<K, V> entry : mapArr[hashcode]
                ) {
                    if (entry.getKey().equals(key)) {
                        return true;
                    }
                }
            }
        } catch (ArrayIndexOutOfBoundsException e) {
            //只要出现数组下标越界就说明没找到,直接返回false
            return false;
        }
        return false;
    }

4、keySet()

  1. 作用很简单,返回一个集合,集合包含了所有的 key 的值
  2. 注意:是 key 的值,而不是哈希值
  3. 思路:
    • 当 hashcodeList 为空时,说明没有哈希值,自然也不存在 key,所以直接返回 null
    • 否则遍历 mapArr 数组,下标为 hashcodeList 存储的哈希值,用 getKey 取出 key
    /**
     * 获取HashMap的键的集合,以Set<K>保存
     *
     * @return 返回key的集合
     */
    @Override
    public Set<K> keySet() {
        //若没有hashcode值,直接返回空
        if (null == hashcodeList) {
            return null;
        } else {
            Set<K> kSet = new HashSet<>();
            for (int i = 0; i < hashcodeList.size(); i++) {
                //遍历 mapArr
                for (Entry<K, V> entry : mapArr[hashcodeList.get(i)]
                ) {
                    kSet.add(entry.getKey());
                }
            }
            return kSet;
        }
    }

5、values()

  1. 与 keySet 类似,作用是返回一个集合,其中包含了所有的 value 值
  2. 思路:
    • 当 hashcodeList 为空时,说明没有哈希值,自然也不存在 key,自然也不存在 value,所以直接返回 null
    • 否则遍历 mapArr 数组,下标为 hashcodeList 存储的哈希值,用 getValue 取出 value
    /**
     * 获取HashMap中value的集合
     *
     * @return 返回value集合
     */
    @Override
    public Collection<V> values() {
        //如果没有hashcode值,则直接返回空
        if (null == hashcodeList) {
            return null;
        } else {
            //生成一个集合
            Collection<V> vCollection = new ArrayList<>();
            for (int i = 0; i < hashcodeList.size(); i++) {
                //遍历 mapArr
                for (Entry<K, V> entry : mapArr[hashcodeList.get(i)]
                ) {
                    vCollection.add(entry.getValue());
                }
            }
            return vCollection;
        }
    }

6、entrySet()

  1. 返回一个集合,包含了所有的键值对及其映射关系
  2. 思路:
    • 当 hashcodeList 为空时,说明没有哈希值,自然也不存在 key,自然也不存在 value,所以直接返回 null
    • 否则遍历 mapArr 数组,下标为 hashcodeList 存的哈希值,直接调用 add 方法添加
    /**
     * 得到 HashMap 中各个键值对映射关系的集合
     *
     * @return 返回一个映射关系的集合
     */
    @Override
    public Set<Entry<K, V>> entrySet() {
        //若没有hashcode值,直接返回空
        if (null == hashcodeList) {
            return null;
        } else {
            Set<Entry<K, V>> entrySet = new HashSet<>();
            for (int i = 0; i < hashcodeList.size(); i++) {
                //遍历 mapArr
                for (Entry<K, V> entry : mapArr[hashcodeList.get(i)]
                ) {
                    entrySet.add(entry);
                }
            }
            return entrySet;
        }
    }

7、size()

  1. size 方法就是返回一个 int 值,是 hashmap 的键值对的数量
  2. 思路:很简单,遍历 hashcodeList,存在一个哈希值就说明存在一对键值对,直接加一即可
    /**
     * 得到 HashMap 键值对的数量
     *
     * @return 一个int型整数
     */
    @Override
    public int size() {
        int count = 0;
        for (int i = 0; i < hashcodeList.size(); i++) {
            count++;
        }
        return count;
    }

有关手撕HashMap(二)的更多相关文章

  1. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  2. 【JavaScript】手撕前端面试题:对象参数浅拷贝 | 简易深拷贝 | 完整深拷贝 - 2

    🖥️NodeJS专栏:Node.js从入门到精通🖥️博主的前端之路(源创征文一等奖作品):前端之行,任重道远(来自大三学长的万字自述)🖥️TypeScript知识总结:TypeScript从入门到精通(十万字超详细知识点总结)🧑‍💼个人简介:大三学生,一个不甘平庸的平凡人🍬👉你的一键三连是我更新的最大动力❤️!文章目录1、浅拷贝要求思路代码2、简易深拷贝要求思路代码3、完整深拷贝要求思路代码1、浅拷贝要求补全JavaScript代码,要求实现一个对象参数的浅拷贝并返回拷贝之后的新对象。注意:参数可能包含函数、正则、日期、ES6新对象是对对象的参数进行浅拷贝,并不是直接对整个对象进行浅拷贝(整个

  3. Ruby - 将数组映射到 HashMap - 2

    我有一个数组和一个返回给定值的值的函数。最终我想创建一个hashmap,它将数组的值作为键值,并将f(key_value)的结果作为值。是否有一种干净、简单的方法,类似于数组的每个/映射,使用block来执行此操作?等价于hsh={}[1,2,3,4].eachdo|x|hsh[x]=f(x)end但看起来更像这个,因为它很简单而且只有一行?results=array.map{|x|f(x)} 最佳答案 请注意,从Ruby2.1.0开始,您还可以使用Array#to_h,像这样:[1,2,3,4].map{|x|[x,f(x)]}.

  4. HashMap中put方法(白话加源码分析) - 2

    一.首先不看代码用白话分析一下流程我们在使用put方法的时候会传进key和value参数在我们将这两个参数传入后,第一步,我们的put方法会去判断这个hashmap是否为null或者长度是否为0,如果是则对hashmap数组进行resize()扩容,第二步,put方法会根据这个key计算hash码来得到数组的位置,(这里需要解释一下,我们的hashmap默认是由一个数组加链表组成的)得到位置后当然是继续判断这个数组下标的值是否为null,为null自然是直接插入我们的value值,如果不为空的话进行第三步第三步,判断key是否为null,当key!=null我们就可以覆盖value值,key=

  5. javascript - node.js 数组实际上是 HashMap 吗? - 2

    令我惊讶的是,这段代码实际上可以在node.js中运行:vararr=newArray();//alsoworks:vararr=[];arr[0]=123;arr['abc']=456;arr;//node.js:[123,abc:456],chrome:[123]我一直认为数组按顺序存储其对象,只能通过整数键访问,就像C++中的std::vector一样。然而,在这里它的行为就像一张map或一个对象。更令人困惑的是,相同的代码在chrome中按预期工作,返回一个包含单个条目123的数组。我认为node.js和chromejavascript使用相同的内部引擎V8。这是怎么回事?

  6. arrays - 如何使用go在没有索引名称的情况下将值存储在hashmap中? - 2

    我想在hashmap中存储一些没有索引名称的值。我的意思是派生自数组和HashMap。示例:{"name":"attn",1,5,6,7,8}变量输出(仅供演​​示):("name":"attn",0:1,1:5,2:6,3:7,4:8,)或者另一个例子:{0:"start","name":"mattn","age":39,"child":[1,2,3,4,5,9:1]}在Go中如何做到这一点?也许我需要新的数据类型?:)请帮帮我!谢谢! 最佳答案 Spec:Compositeliterals:Thekeyisinterpreted

  7. 我的 HashMap 实现的性能改进 - 2

    我决定尝试制作自己的HashMap(here)对于读取,它比标准库实现慢28%,我想知道是否可以加快以下代码的速度,Index(),这对查找至关重要:constnumOnes=uint8(20)constones=uint32(1>numOnesstart:=m.starts[part]bitsNum:=m.bitNums[part]matchedBits:=bitsNum&uint16(remaining)offset:=BitScoreCache[bitsNum][matchedBits]returnstart+uint32(offset)}请注意BitScoreCache是var

  8. generics - Go 中的通用 hashmap - 2

    我正在尝试为map类型制作一个包装器,以便我可以添加一些方法,例如contains()(这几乎让我想念Java).但是,我不知道我是否可以在Java中做类似泛型的事情。虽然我读过的几乎所有内容都说Go没有泛型类型,但肯定有比为我正在使用的每个可能的结构和值组合编写一个单独的结构更好的方法。这是我正在尝试做的,即使代码不起作用:funcnewMap(keyinterface{},valinterface{}){keytype:=key.(type)valtype:=val.(type)returnhashmap{map[keytype]valtype}}typehashmapstruct

  9. java - 将关联数组(Hashmap)作为参数传递给 xml rpc - 2

    我想从Java进行XML-RPC,我在将关联数组(Hashmap)作为参数传递时遇到问题。这是我的代码。XmlRpcClientConfigImplconfig=newXmlRpcClientConfigImpl();config.setServerURL(newURL(ServeUrl));XmlRpcClientclient=newXmlRpcClient();client.setConfig(config);Mapmap=newHashMap();map.put(ParameterName,ParameterValue);map.put(ParameterName,Paramet

  10. java - 从 xml(java) 填充 hashmap - 2

    我的xml看起来像:Light1ben1Light2crux2Light3let3Light1let4Light1let1当我在解析xml时尝试填充hashmap时出现问题。我正在使用四个hashmap,每个hashmap用于保存不同级别的信息。所以最终的hashmap由来自较低级别的hashmap组成,如setup、group和light,每个级别的属性是该级别各自映射的键。publicHashMaplightContent=newHashMap();publicHashMap>groupContent=newHashMap>();publicHashMap>>setupConten

随机推荐