手撕HashMap(二)

yizhihongxing
  • 这里再补充几个手撕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;
    }

原文链接:https://www.cnblogs.com/lynnier/p/17270880.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:手撕HashMap(二) - Python技术站

(0)
上一篇 2023年4月18日
下一篇 2023年4月18日

相关文章

  • Java 数据结构算法Collection接口迭代器示例详解

    Java 数据结构算法 Collection 接口迭代器示例详解 如果你正在学习 Java 编程,那么数据结构和算法一定是一个不可避免的话题。在 Java 中,Collection 框架提供了许多有用的接口和类来管理和操作集合。其中,迭代器 Iterator 是 Collection 中最重要的接口之一,它提供了对集合元素进行迭代的方法。本文将对 Java …

    数据结构 2023年5月17日
    00
  • C语言数据结构系列之树的概念结构和常见表示方法

    C语言数据结构系列之树的概念结构和常见表示方法 树是一种非线性数据结构,它由若干个节点构成,节点之间通过边来连接,具有层次关系。 树的基本概念和术语 节点:树中的元素,它可以包含一个数据元素或多个数据元素,一个节点也可以称为一个分支节点。 根节点:树的最上层节点,它没有父节点。 叶子节点:没有子节点的节点称为叶子节点。 父节点和子节点:父节点是某个节点的上一…

    数据结构 2023年5月17日
    00
  • python 如何实现遗传算法

    Python实现遗传算法的完整攻略 遗传算法是一种基于自然选择和遗传机制的优化算法,常用于求解复杂的优问题。本文将详细讲解Python实现遗传算法的完整攻略,包括算法原理、Python实现过程和示例。 算法原理 遗传算法的基本思想是:通过模拟自然界的进化过程,不断地从种群中选择优秀的个体,交叉和变异产生新的个,最终到适应度更高的个体。具体实现过程如下: 初始…

    python 2023年5月13日
    00
  • python实现动态规划算法的示例代码

    Python实现动态规划算法的完整攻略 动态规划算法是一种常用的算法,它可以用于解决多种实际问题。在本文中,我们将介绍动态规划算法的基本原理,并提供两个示例,以说明如何使用Python实现动态规划算法。 动态规划算法的基本原理 动态规划算法是一种通过将问题解成子问题来求解复杂问题的算法。在动态规划算法中,我们通常使用一个数组来存储子问题的解,避免重复计算。动…

    python 2023年5月14日
    00
  • 拓扑排序Python实现的过程

    拓扑排序Python实现的过程 拓扑排序是一种常用的有向无环图(DAG)的排序算法,它可以将DAG中的节点按照一定的顺序进行排序。实际应用中,拓扑排序常于任务调度、依赖关系分析等场景。本文将介绍拓扑排序的Python实现过程,并提供两个示例说明。 拓扑排序的实现过程 拓扑排序的实现过程可以分为以下几个步骤: 构建DAG:将有向表示为邻接表或邻接矩阵的形式。 …

    python 2023年5月14日
    00
  • Python常用模块介绍

    以下是关于“Python常用模块介绍”的完整攻略: 简介 Python是一种功能强大的编程语言,它有许多内置模块和第三方模块,可以帮助我们更轻松地完成各种任务。在本教程中,我们将介绍一些常用的Python模块,并提供两个示例说明。 常用Python模块介绍 NumPy NumPy是Python中用于科学计算的基本软件包之一。它提供了一个强大的N维数组对象,以…

    python 2023年5月14日
    00
  • C语言数据结构算法基础之循环队列示例

    标题:C语言数据结构算法基础之循环队列示例 1. 简介 循环队列是一种常见的数据结构,它采用固定大小的数组来模拟队列的数据结构,可以高效地处理队列的进出操作。本文将会讲解循环队列的实现原理和示例代码。 2. 循环队列基本原理 循环队列通过两个指针front和rear来实现队列的添加和删除操作。在初始化时,front和rear的初始值都为0。每当数据进入队列时…

    数据结构 2023年5月17日
    00
  • 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解

    解析从源码分析常见的基于Array的数据结构动态扩容机制的详解 什么是动态扩容机制 动态扩容机制是指,当一个数据结构达到其容量限制时,自动增加容量大小以继续存储新的数据。在动态扩容时,需要考虑到时间和空间的平衡,因为扩容需要分配新的内存空间,在处理大量数据时,需要尽可能减少空间浪费和分配内存的时间消耗。 基于Array的数据结构 Array是一种连续存储的数…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部