HashMap之JAVA实现



HashMap是使用最频繁、最重要的数据结构之一,提供了字典操作功能,Insert、Search、Delete操作的效率都很高。本文将尝试用Java实现一个最简单的HashMap。因为简单,才容易看到HashMap的本真设计思想。

什么是Hash

依我的理解,Hash就是把一个对象转化为一个正整数的过程。相同的对象产生相同的Hash Code,但不同的对象的Hash Code具有随机的特点,不同的Hash Code均匀分布。不同的对象也可能Hash Code相同,产生碰撞。

为什么Hash

Map存储的是键值对,存储的方式一般通过数组来完成。假设Key的可能集合为S,如果不Hash,那么要创建一个size大于等于S.length的数组来存储键,否则某些Key可能找不到槽位来放数据。当S很大,而真正使用到的数据又相对较小的时候,会造成空间的浪费。把S映射到一个较小的集合R,Hash正好用来做这样的Mapping,只不过得到的整数要处理一下,大小控制在R的范围之内。

具体实现

主要包括Insert(新增),Put(新增或者修改),Search(查询),Delete(删除)四个操作。Hash的过程利用了Object的hashcode(),也参考了算法导论的乘法Hash算法。解决碰撞使用了链表法,注意Node的next属性。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class HashMap<K, V> {  
  2.     private static int DEFAULT_CAPACITY = 16;  
  3.     private static double A = (Math.pow(50.5) - 1) / 2;  
  4.   
  5.     private int capacity;  
  6.     private int size = 0;  
  7.   
  8.     private Node<K, V>[] buckets;  
  9.   
  10.     public HashMap() {  
  11.         this(DEFAULT_CAPACITY);  
  12.     }  
  13.   
  14.     @SuppressWarnings("unchecked")  
  15.     public HashMap(int capacity) {  
  16.         if (capacity <= 0) {  
  17.             throw new IllegalArgumentException(  
  18.                     "capacity can not be negative or zero");  
  19.         }  
  20.   
  21.         // 保证 capacity 是2的n次方  
  22.         int temp = 1;  
  23.         while (temp < capacity) {  
  24.             temp <<= 2;  
  25.         }  
  26.         this.capacity = temp;  
  27.   
  28.         buckets = new Node[this.capacity];  
  29.     }  
  30.   
  31.     public void insert(K key, V value) {  
  32.         if (key == null) {  
  33.             throw new IllegalArgumentException("key can not be null");  
  34.         }  
  35.   
  36.         int position = index(key);  
  37.   
  38.         Node<K, V> node = new Node<K, V>(key, value);  
  39.         if (buckets[position] != null) {  
  40.             node.setNext(buckets[position]);  
  41.         }  
  42.   
  43.         buckets[position] = node;  
  44.         size++;  
  45.     }  
  46.   
  47.     public void put(K key, V value) {  
  48.         if (key == null) {  
  49.             throw new IllegalArgumentException("key can not be null");  
  50.         }  
  51.   
  52.         int position = index(key);  
  53.   
  54.         Node<K, V> node = buckets[position];  
  55.   
  56.         while (node != null) {  
  57.             if (node.key.equals(key)) {  
  58.                 node.value = value;  
  59.                 return;  
  60.             }  
  61.   
  62.             node = node.next;  
  63.         }  
  64.   
  65.         Node<K, V> newNode = new Node<K, V>(key, value);  
  66.         if (buckets[position] != null) {  
  67.             newNode.setNext(buckets[position]);  
  68.         }  
  69.   
  70.         buckets[position] = newNode;  
  71.         size++;  
  72.     }  
  73.   
  74.     public void delete(K key) {  
  75.         if (key == null) {  
  76.             throw new IllegalArgumentException("key can not be null");  
  77.         }  
  78.   
  79.         int position = index(key);  
  80.         Node<K, V> node = buckets[position];  
  81.   
  82.         if (node == null) {  
  83.             return;  
  84.         }  
  85.   
  86.         if (node.key.equals(key)) {  
  87.             buckets[position] = node.next;  
  88.             size--;  
  89.         }  
  90.   
  91.         while (node.next != null) {  
  92.             if (node.next.key.equals(key)) {  
  93.                 node.next = node.next.next;  
  94.                 size--;  
  95.                 break;  
  96.             }  
  97.   
  98.             node = node.next;  
  99.         }  
  100.     }  
  101.   
  102.     public V search(K key) {  
  103.         if (key == null) {  
  104.             throw new IllegalArgumentException("key can not be null");  
  105.         }  
  106.   
  107.         int position = index(key);  
  108.         Node<K, V> node = buckets[position];  
  109.   
  110.         while (node != null) {  
  111.             if (node.key.equals(key)) {  
  112.                 return node.value;  
  113.             }  
  114.   
  115.             node = node.next;  
  116.         }  
  117.   
  118.         return null;  
  119.     }  
  120.   
  121.     public int size() {  
  122.         return size;  
  123.     }  
  124.   
  125.     public boolean isEmpty() {  
  126.         return size == 0;  
  127.     }  
  128.   
  129.     @Override  
  130.     public String toString() {  
  131.         StringBuffer buffer = new StringBuffer();  
  132.         buffer.append("{");  
  133.   
  134.         for (int i = 0; i < capacity; i++) {  
  135.             Node<K, V> node = buckets[i];  
  136.             while (node != null) {  
  137.                 buffer.append(node.key + ":" + node.value + ", ");  
  138.                 node = node.next;  
  139.             }  
  140.         }  
  141.   
  142.         if (buffer.length() > 1) {  
  143.             buffer.delete(buffer.length() - 2, buffer.length());  
  144.         }  
  145.   
  146.         buffer.append("}");  
  147.   
  148.         return buffer.toString();  
  149.     }  
  150.   
  151.     private int index(K key) {  
  152.         int hashCode = key.hashCode();  
  153.   
  154.         double temp = hashCode * A;  
  155.         double digit = temp - Math.floor(temp);  
  156.   
  157.         return (int) Math.floor(digit * capacity);  
  158.     }  
  159.   
  160.     static class Node<K, V> {  
  161.         private final K key;  
  162.         private V value;  
  163.         private Node<K, V> next;  
  164.   
  165.         public Node(K key, V value) {  
  166.             this.key = key;  
  167.             this.value = value;  
  168.         }  
  169.   
  170.         public V getValue() {  
  171.             return value;  
  172.         }  
  173.   
  174.         public void setValue(V value) {  
  175.             this.value = value;  
  176.         }  
  177.   
  178.         public Node<K, V> getNext() {  
  179.             return next;  
  180.         }  
  181.   
  182.         public void setNext(Node<K, V> next) {  
  183.             this.next = next;  
  184.         }  
  185.   
  186.         public K getKey() {  
  187.             return key;  
  188.         }  
  189.     }  
  190.   
  191.     public static void main(String[] args) {  
  192.         HashMap<String, String> map = new HashMap<String, String>();  
  193.         map.put("001""James");  
  194.         map.put("002""Antony");  
  195.         map.put("003""Bosh");  
  196.         map.put("004""Wade");  
  197.         map.put("004""WestBrook");  
  198.   
  199.         System.out.println(map);  
  200.         System.out.println(map.size());  
  201.         System.out.println(map.search("004"));  
  202.     }  
  203. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值