对 HashMap 的一次扩展

一、需求

(1) 容量200 Capacity = 200.                       ——> 静态数据,可提供设置.
(2) 最近操作(get/put)的元数,总放在最前.          ——> 元素频繁位移,从效率考虑,用链表实现.
(3) 超过 Capacity 值后,移除最后一个元素,即第200号元素.   ——> 结合下一条,满载后,可能频繁操作末端元素,考虑用双向链表.

二、数据结构设计

 1     @RequiredArgsConstructor
 2     class ButterHashMap<K,V> extends LinkedHashMap<K,V>{
 3         @NonNull
 4         @Getter@Setter
 5         int capacity;           // 容量值
 6         @Getter@Setter
 7         int limit;              // 当前已用量
 8         DoubleLinkedNode table;
 9 
10         @RequiredArgsConstructor
11         class DoubleLinkedNode<K,V> extends LinkedHashMap {
12             @NonNull
13             @Getter
14             @Setter
15             K k;
16             @NonNull
17             @Getter
18             @Setter
19             V v;
20             DoubleLinkedNode head;
21             DoubleLinkedNode pre;
22             @Getter@Setter
23             DoubleLinkedNode next;
24             DoubleLinkedNode tail;
25         }
26 
27     }
数据结构

三、功能实现

  1     @RequiredArgsConstructor
  2     class ButterHashMap<K,V> extends LinkedHashMap<K,V>{
  3         @Override
  4         public V put(K key,V value){
  5             if(checkCapacity()){
  6                 // 容量未满:添加首节点
  7                 this.createNode(key, value, false);
  8             }else{
  9                 // 容量已满:添加首节点,移除尾节点
 10                 this.createNode(key, value, true);
 11             }
 12             System.out.println("添加后——limit : "+ limit + ", capacity : "+ capacity);
 13             return value;
 14         }
 15 
 16         private boolean checkCapacity(){
 17             int flag = limit+1;
 18             if(flag > capacity) return false;
 19             return true;
 20         }
 21 
 22         // 不能判断 是否存在 K-V,因为 V 可能正好为 null;
 23         public V getValue(K key){
 24             DoubleLinkedNode<K,V> e = getNode(key);
 25             if(e != null) return e.v;
 26             return null;
 27         }
 28         
 29         private DoubleLinkedNode createNode(K key,V value,boolean isFlow){
 30             // 先查询一下
 31             DoubleLinkedNode src = this.getNode(key);
 32             if(src != null){
 33                 // 有值,替换 value 即可
 34                 src.setV(value);
 35                 return src;
 36             }
 37 
 38             DoubleLinkedNode newNode = new DoubleLinkedNode(key, value);
 39             if(!isFlow && limit == 0){
 40                 this.table = newNode.head = newNode.tail = newNode;
 41                 limit++;
 42                 return this.table;
 43             }
 44 
 45             this.table.pre = newNode;
 46             newNode.next = this.table;
 47             newNode.tail = this.table.tail;
 48             this.table = newNode;
 49             this.table.head = newNode;
 50             if(isFlow){
 51                 // 容量已满:尾节点,向前移一个节点,节点总数不变
 52                 this.table.tail = this.table.tail.pre;
 53                 // 相当于移除原来的尾节点
 54                 this.table.tail.next = null;
 55             }else{
 56                 limit++;
 57             }
 58             return this.table;
 59         }
 60 
 61         // 提供 public 的原因在于,本方法 能判断 是否存在 K-V. 若存在,返回值不为 null.
 62         public DoubleLinkedNode<K,V> getNode(K key){
 63             if (this.table == null) return null;
 64 
 65             DoubleLinkedNode<K,V> t = this.table,c = this.table,
 66                     stop =  this.table.head,h = this.table.head;
 67             // t:table, c:change, h:head
 68             while (c.getK() != key){
 69                 c = c.next;
 70                 if(c == null || stop == c){
 71                     // 未找到节点
 72                     return null;
 73                 }
 74             }
 75 
 76             // A : getA
 77             // tail、head 无需调整
 78             if(h.next == null){
 79                 return h;
 80             }
 81 
 82             // A ——> B : getA : B ——> A
 83             // tail 有影响,需要调整;head 需要调整
 84             if(c.next == null){
 85                 c.pre.next = null;
 86                 c.pre.tail = c.pre;
 87                 c.tail = c.pre;
 88 
 89                 c.next = t.head;
 90                 t.head = c;
 91                 t.pre = c;
 92                 c.next = t;
 93                 t.tail = c.pre;
 94 
 95                 c.head = c;
 96                 c.tail = c.pre;
 97                 c.pre = null;
 98                 this.table = c;
 99                 this.table.head = c;
100                 this.table.next = h;
101                 this.table.tail = c.tail;
102                 return c;
103             }
104 
105             // A ——> B ——> C:getB:A ——> C ——> B
106             // tail 无影响,无需调整;head 需要调整
107             c.next.pre = c.pre;
108             c.pre.next = c.next;
109             c.next.head = c;
110             c.pre.head = c;
111 
112             h.head = c;
113             h.pre = c;
114             c.next = t;
115             c.head = c;
116 
117             c.pre = null;
118             this.table = c;
119             this.table.head = c;
120             this.table.next = h;
121             return c;
122         }
123     }
完善 ButterHashMap<K,V> 功能,省略了上面数据结构的代码(他们是一起的)

四、测试检验

 1 package test;
 2 
 3 import lombok.*;
 4 
 5 import java.util.*;
 6 
 7 
 8 public class ButterHashMapTest {
 9 
10 public static void main(String[] args) {
11 
12     ButterHashMapTest bt = new ButterHashMapTest();
13     bt.testButterHashMap();
14 }
15 
16     void testButterHashMap(){
17         ButterHashMap betterHashMap = new ButterHashMap(5);
18         betterHashMap.put("a",1);
19         betterHashMap.put("b",2);
20         betterHashMap.put("c",3);
21         betterHashMap.put("d",4);
22         this.printMap("put(d-4)", betterHashMap);
23         betterHashMap.put("e",5);
24         this.printMap("put(e-5)", betterHashMap);
25         betterHashMap.put("c",33);
26         System.out.println("========添加相同的 ‘c’:33 《《 ============");
27         this.printMap("put(e-5)", betterHashMap);
28         System.out.println("========添加相同的 ‘c’:33  》》============");
29         betterHashMap.put("f",6);
30         this.printMap("put(f-6)", betterHashMap);
31         betterHashMap.getValue("e");
32         this.printMap("getE", betterHashMap);
33     }
34 
35     public void printMap(String context, ButterHashMap betterHashMap){
36         System.out.println("打印" +context+ "开始《《《===============");
37         if(betterHashMap != null){
38             ButterHashMap.DoubleLinkedNode p = betterHashMap.table,
39                     s = p;
40             while (s != null){
41                 System.out.println("key:"+s.k + ", value:" + s.v);
42                 s = s.next;
43             }
44 
45             System.out.println("打印" +context+ "结束》》》===============");
46 
47         }
48     }
49 }
测试代码

五、测试结果

 1 添加后——limit : 1, capacity : 5
 2 添加后——limit : 2, capacity : 5
 3 添加后——limit : 3, capacity : 5
 4 添加后——limit : 4, capacity : 5
 5 打印put(d-4)开始《《《===============
 6 key:d, value:4
 7 key:c, value:3
 8 key:b, value:2
 9 key:a, value:1
10 打印put(d-4)结束》》》===============
11 添加后——limit : 5, capacity : 5
12 打印put(e-5)开始《《《===============
13 key:e, value:5
14 key:d, value:4
15 key:c, value:3
16 key:b, value:2
17 key:a, value:1
18 打印put(e-5)结束》》》===============
19 添加后——limit : 5, capacity : 5
20 ========添加相同的 ‘c’:33 《《 ============
21 打印put(e-5)开始《《《===============
22 key:c, value:33
23 key:e, value:5
24 key:d, value:4
25 key:b, value:2
26 key:a, value:1
27 打印put(e-5)结束》》》===============
28 ========添加相同的 ‘c’:33  》》============
29 添加后——limit : 5, capacity : 5
30 打印put(f-6)开始《《《===============
31 key:f, value:6
32 key:c, value:33
33 key:e, value:5
34 key:d, value:4
35 key:b, value:2
36 打印put(f-6)结束》》》===============
37 打印getE开始《《《===============
38 key:e, value:5
39 key:f, value:6
40 key:c, value:33
41 key:d, value:4
42 key:b, value:2
43 打印getE结束》》》===============
44 
45 Process finished with exit code 0
测试结果,实现功能


原文地址:https://www.cnblogs.com/bridgestone29-08/p/13070113.html