首页 > 其他分享 >手写HashMap基础部分代码

手写HashMap基础部分代码

时间:2024-03-03 18:00:11浏览次数:19  
标签:node Node HashMap 代码 value key table 手写 null

代码展示:

package com.north.hashmap;

import java.util.Map;

/**
 * @Author North
 * @Date 2024/3/3
 * 手写HashMap
 */
@SuppressWarnings("all")
public class MyHashMap<K , V> {
    /**
     * 哈希表
     */
    private Node<K,V>[] table;

    /**
     * 键值对的个数
     */
    private int size;

    @SuppressWarnings("unchecked")
    public MyHashMap() {
        // 注意:new数组的时候,不能使用泛型。这样写是错误的:new Node<K,V>[16];
        this.table = new Node[16];
    }

    static class Node<K,V>{
        /**
         * key的hashCode()方法的返回值。
         * 哈希值,哈希码
         */
        int hash;
        /**
         * key
         */
        K key;
        /**
         * value
         */
        V value;
        /**
         * 下一个结点的内存地址
         */
        Node<K,V> next;

        /**
         * 构造一个结点对象
         * @param hash 哈希值
         * @param key 键
         * @param value 值
         * @param next 下一个结点地址
         */
        public Node(int hash, K key, V value, Node<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        @Override
        public String toString(){
            return "["+key+", "+value+"]";
        }
    }

    /**
     * 获取集合中的键值对的个数
     * @return 个数
     */
    public int size(){
        return size;
    }

    /**
     * 向MyHashMap集合中添加一个键值对。
     * @param key 键
     * @param value 值
     * @return value,如果key重复,则返回oldValue,如果key不重复,则返回newValue
     */
    public V put(K key, V value){
        /*
        【第一步】:处理key为null的情况
            如果添加键值对的key就是null,则将该键值对存储到table数组索引为0的位置。
        【第二步】:获得key对象的哈希值
            如果添加键值对的key不是null,则就调用key的hashcode()方法,获得key的哈希值。
        【第三步】:获得键值对的存储位置
            因为获得的哈希值在数组合法索引范围之外,因此我们就需要将获得的哈希值转化为[0,数组长度-1]范围的整数,
            那么可以通过取模法来实现,也就是通过“哈希值 % 数组长度”来获得索引位置(i)。
        【第四步】:将键值对添加到table数组中
            当table[i]返回结果为null时,则键键值对封装为Node对象并存入到table[i]的位置。
            当table[i]返回结果不为null时,则意味着table[i]存储的是单链表。我们首先遍历单链表,如果遍历出来节点的
            key和添加键值对的key相同,那么就执行覆盖操作;如果遍历出来节点的key和添加键值对的key都不同,则就将键键
            值对封装为Node对象并插入到单链表末尾。
         */
        if(key == null){
            return putForNullKey(value);
        }
        // 程序执行到此处说明key不是null
        // 获取哈希值
        int hash = key.hashCode();
        // 将哈希值转换成数组的下标
        int index = Math.abs(hash % table.length);
        // 取出下标index位置的Node
        Node<K,V> node = table[index];
        if(null == node){
            table[index] = new Node<>(hash, key, value, null);
            size++;
            return value;
        }
        // 有单向链表(遍历单向链表,尾插法)
        Node<K,V> prev = null;
        while(null != node){
            if(node.key.equals(key)){
                V oldValue = node.value;
                node.value = value;
                return oldValue;
            }
            prev = node;
            node = node.next;
        }
        prev.next = new Node<>(hash, key, value, null);
        size++;
        return value;
    }

    private V putForNullKey(V value) {
        Node<K,V> node = table[0];
        if(node == null){
            table[0] = new Node<>(0, null,value,null);
            size++;
            return value;
        }
        // 程序可以执行到此处,说明下标为0的位置上有单向链表
        Node<K, V> prev = null;
        while(node != null){
            if(node.key == null){
                V oldValue = node.value;
                node.value = value;
                return oldValue;
            }
            prev = node;
            node = node.next;
        }
        prev.next = new Node<>(0, null,value,null);
        size++;
        return value;
    }

    /**
     * 通过key获取value
     * @param key 键
     * @return 值
     */
    public V get(K key){
        /*
        【第一步】:处理key为null的情况
        如果查询的key就是null,则就在table数组索引为0的位置去查询。
        【第二步】:获得key对象的哈希值
        如果查询的key不是null,则就调用key的hashcode()方法,获得key的哈希值。
        【第三步】:获得键值对的存储位置
        因为获得的哈希值在数组合法索引范围之外,因此我们就需要将获得的哈希值转化为[0,数组长度-1]范围的整数,
        那么可以通过取模法来实现,也就是通过“哈希值 % 数组长度”来获得索引位置(i)。
        【第四步】:遍历单链表,根据key获得value值
        如果table[i]返回的结果为null,则证明单链表不存在,那么返回null即可
        如果table[i]返回的结果不为null时,则证明单链表存在,那么就遍历整个单链表。如果遍历出来节点的key和查询
        的key相同,那么就返回遍历出来节点的value值;如果整个单链表遍历完毕,则遍历出来节点的key和查询的key都不
        相等,那么就证明查询key在链表中不存在,则直接返回null即可。
         */
        if(null == key){
            Node<K,V> node = table[0];
            if(null == node){
                return null;
            }
            // 程序执行到这里,数组下标为0的位置不是null。就是有单向链表。
            while(node != null){
                if(null == node.key){
                    return node.value;
                }
                node = node.next;
            }
        }
        // key不是null
        int hash = key.hashCode();
        int index = Math.abs(hash % table.length);
        Node<K,V> node = table[index];
        if(null == node){
            return null;
        }
        while(null != node){
            if(node.key.equals(key)){
                return node.value;
            }
            node = node.next;
        }
        return null;
    }

    /**
     * 重写toString方法,直接输出Map集合是会调用。
     * @return ""
     */
    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < table.length; i++) {
            Node<K,V> node = table[i];
            // 如果node不是空,就遍历整个单向链表
            while(node != null){
                sb.append(node);
                node = node.next;
            }
        }
        return sb.toString();
    }
}

标签:node,Node,HashMap,代码,value,key,table,手写,null
From: https://www.cnblogs.com/NorthPoet/p/18050378/HashMap

相关文章

  • 云原生基础设施代码化-terragrunt处理
    Terragrunt是什么?Terragrunt是一个基于Terraform的开源工具,它通过向Terraform添加一些额外的功能来帮助管理和组织Terraform代码。它提供了许多功能,包括:DRY(Don’tRepeatYourself):使用Terragrunt可以减少Terraform代码冗余。例如,您可以将共享的配置块抽象为公共模块,然后在需......
  • 根据建表sql语句生成go的struct代码工具
    sql2struct一个根据"CREATETABLE"建表语句生成对应的Go语言结构体的工具,暂只支持MySQL表。开发目的在github中找到一些sql2struct,但要么是chrome插件,要么是在线工具,要么是需要连接MySQL,不是很方便。本sql2struct根据SQL文件中的建表语句来生成Go的struct,可集成......
  • python邮件发送代码参考
    1.python邮件发送参考代码#!/usr/bin/python#-*-coding:UTF-8-*-importsmtplibfromemail.mime.imageimportMIMEImagefromemail.mime.textimportMIMETextfromemail.mime.multipartimportMIMEMultipartfromemail.headerimportHeader#第三方SMTP服务mail_host......
  • pycharm下master代码回滚了,dev提交了新代码,dev merge master有冲突解决
    在PyCharm的右下角,点击"Git:master",在弹出的菜单中选择"master"分支,然后点击"Checkout"。在菜单栏中,选择"VCS"->"Git"->"Log",在弹出的窗口中找到被回滚的提交,右键点击这个提交,然后选择"RevertCommit"。这将创建一个新的提交,恢复被回滚的更改。然后在右下角,点击&qu......
  • 动手学强化学习(五):值迭代与策略迭代代码
    一、策略迭代importcopyclassCliffWalkingEnv:"""悬崖漫步环境"""def__init__(self,ncol=12,nrow=4):self.ncol=ncol#定义网格世界的列self.nrow=nrow#定义网格世界的行#转移矩阵P[state][action]=[(p,next_state,......
  • day52 动态规划part10 代码随想录算法训练营 122. 买卖股票的最佳时机 II
    题目:122.买卖股票的最佳时机II我的感悟:只要定义清楚,就可以做出来的。理解难点:先判断等于听课笔记:看了文字版本,感觉还是我的思路最牛逼!!我的代码:classSolution:defmaxProfit(self,prices:List[int])->int:#dp[i]为截止到当前能获得的最大利润......
  • day53 动态规划part10 代码随想录算法训练营 121. 买卖股票的最佳时机
    题目:121.买卖股票的最佳时机我的感悟:soeasy 打印dp确实能发现问题理解难点:注意条件,及时更新dp听课笔记:看了,老师的代码,感觉没有我的简洁,哈哈!!我的代码:classSolution:defmaxProfit(self,prices:List[int])->int:#设dp[i]为截止到当前能获得......
  • day52 动态规划part9 代码随想录算法训练营 337. 打家劫舍 III
    题目:337.打家劫舍III我的感悟:跳过,目前树的不学理解难点:树的理解,以及树的遍历听课笔记:我的代码:通过截图:老师代码:#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#......
  • day52 动态规划part9 代码随想录算法训练营 213. 打家劫舍 II
    题目:213.打家劫舍II我的感悟:看了题解不难,就是环这个思路转化很重要!理解难点:环的转化为,首,尾。代码上面可以省略长度为2的校验听课笔记:分3中情况:不考虑首尾|考虑首|考虑尾而情况2和情况3包含了情况1我的代码:classSolution:defrob(self,nums:List[i......
  • 编写更好的C#代码的技巧
    转载:https://blog.csdn.net/WuLex/article/details/123353742?spm=1001.2101.3001.6650.6&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-6-123353742-blog-101057958.pc_relevant_3mothn_strategy_and_data_recovery&depth_......