• 手写一个HashMap


    前言 

            为了加深对于HashMap的理解,可以手写HashMap理解底层操作原理

            我们知道HashMap在jdk1.8之后使用了数组 + 链表 + 红黑树的结构,那么在自己实现HashMap的时候需要注意这一点;我将手动实现HashMap的节点、get()、put()方法

    1.get()方法的流程

    • 通过 key 进行hash运算,得到 index
    • 判断 index 是否为空,为空则返回 null
    • 不为空,则判断传入的当前节点是否有 next ,为链表还是红黑树,遍历链表或红黑树返回值

    2.put()方法的流程

    • 求出 key 的哈希值,得到 index,并得到 index 对应的对象
    • 如果 index 的对象为空,则直接赋值
    • 如果当前 index 的对象不为空,则使用链表存储

    3.手写Map接口

    先自定义一个Map接口

    1. public interface MyMap{
    2. int size();
    3. V put(K k, V v);
    4. V get(K k);
    5. V remove(K k);
    6. interface Entry(K, V){
    7. K getKey();
    8. V getValue();
    9. }
    10. }

    自定义一个Entry

    1. class Entry implements MyMap.Entry{
    2. int hash;
    3. K k;
    4. V v;
    5. Entry next;
    6. public ENtry(K k, V v, Entry next, int hash){
    7. this.k = k;
    8. this.v = v;
    9. this.hash = hash;
    10. this.next = next;
    11. }
    12. public K getKey(){
    13. return k;
    14. }
    15. public V getValue(){
    16. return v;
    17. }
    18. }

    4.自定义put()、get()、remove()方法

    1. public class MyHashMap implements MyMap{
    2. Entry[] table = null;
    3. int size = 0;
    4. public MyHashMap(){
    5. table = new Entry[16];
    6. }
    7. public int size(){
    8. return size;
    9. }
    10. //自定义的put()
    11. public V put(K k, V v){
    12. //该key的索引:存储在entry数组中的位置
    13. int index = hash(k);
    14. //该key的哈希值
    15. int hash = k.hashCode();
    16. Entry entry = table[index];
    17. if(entry == null){
    18. table[index] = new Entry<>(k, v, null, hash);
    19. size++;
    20. }else{
    21. table[index] = new Entry<>(k, v, entry, hash);
    22. }
    23. return (V)table[index].getValue();
    24. }
    25. private int hash(K k){
    26. int index = k.hashCode() % (table.length - 1);
    27. if(index < 0){
    28. return -index;
    29. }
    30. return index;
    31. }
    32. //自定义get()方法
    33. public V get(K k){
    34. int index = hash(K);
    35. int hash = k.hashCode();
    36. Entry entry = table[index];
    37. if(entry == null){
    38. return null;
    39. }else{
    40. //不为空,则比较输入的key 和 存在于哈希表中的key相比较;相同则返回数据
    41. if(entry.getKey() == k && hash = entry.hash){
    42. return entry.getValue();
    43. }
    44. //遍历节点,找到相同的值
    45. Entry next = entry.next;
    46. while(null != next){
    47. if(entry.getKey() == k && hash = entry.hash){
    48. return entry.getValue();
    49. }
    50. next = next.next;
    51. }
    52. }
    53. return null;
    54. }
    55. //自定义remove()方法
    56. public V remove(K k){
    57. int index = hash(K);
    58. int hash = k.hashCode();
    59. Entry entry = table[index];
    60. if(entry == null){
    61. return null;
    62. }else{
    63. if(entry.getKey() == k && entry.hash = hash){
    64. entry = entry.next;
    65. table[index] = entry;
    66. return (V)table[index];
    67. }
    68. if(null != entry.next){
    69. Entry head = entry;
    70. Entry p = head;
    71. EntryV next = head.next;
    72. do{
    73. if(next.getKey() == k && next.hash == has){
    74. p.next = next.next;
    75. break;
    76. }
    77. p = next;
    78. next = next.next;
    79. }while(next != null);
    80. }else{
    81. table[index] = null;
    82. }
    83. return table[index] == null ? null : (V)table[index].getValue();
    84. }
    85. }

  • 相关阅读:
    使用XXL-JOB自定义任务并调度
    关于大型语言模型的争论和局限
    Vue中实现3D得球自动旋转
    STM32中五个时钟源:HSI、HSE、LSI、LSE、PLL
    CentOS7 firewall使用(开放和禁止端口、端口转发)
    subline ts 环境配置
    【LeetCode48:旋转图像(附Java代码)】
    【CSS基础】
    Flink Yarn Per Job - 提交流程一
    【IEEE独立出版、有确定的ISBN号】第三届能源与电力系统国际学术会议 (ICEEPS 2024)
  • 原文地址:https://blog.csdn.net/ggggggzzzzz/article/details/132893086