LRU演算法實現
阿新 • • 發佈:2020-10-28
1.lru快取策略
構成要素有兩個:記憶體大小和替換策略.
實現方法:hashtable+雙向連結串列
查詢時間複雜度o(1),修改更新時間複雜度o(1).
2.lru工作原理
1 1.題目地址:https://leetcode-cn.com/problems/lru-cache/ 2 2.題目內容:LRU快取機制(中等) 3 4 運用你所掌握的資料結構,設計和實現一個LRU(最近最少使用)快取機制.它應該支援以下操作:獲取資料get和寫入資料put. 5 6 獲取資料get(key)-如果關鍵字(key)存在於快取中,則獲取關鍵字的值(總是正數),否則返回-1.7 寫入資料put(key,value)-如果關鍵字已經存在,則變更其資料值;如果關鍵字不存在,則插入該組[關鍵字/值].當快取容量達到上限時,它應該在寫入新資料之前刪除最久未使用的資料值,從而為新的資料值留出空間. 8 9 示例: 10 LRUCache cache = new LRUCache( 2 /* 快取容量 */ ); 11 12 cache.put(1, 1); 13 cache.put(2, 2); 14 cache.get(1); // 返回 1 15 cache.put(3, 3); // 該操作會使得關鍵字 2 作廢 16 cache.get(2); //返回 -1 (未找到) 17 cache.put(4, 4); // 該操作會使得關鍵字 1 作廢 18 cache.get(1); // 返回 -1 (未找到) 19 cache.get(3); // 返回 3 20 cache.get(4); // 返回 4 21 22 第一步:確定題目要實現的主要業務功能 23 第二步:實現業務功能的單元 24 第三步:組裝實現業務功能的單元 25 26 4.lru(雜湊表+雙向連結串列) 27 28 public class Lru { 29 // 1.定義雙向連結串列 30 classDoubleLinkNode { 31 int key; 32 int value; 33 DoubleLinkNode prev; 34 DoubleLinkNode next; 35 36 public DoubleLinkNode() {} 37 38 public DoubleLinkNode(int key, int value) { 39 this.key = key; 40 this.value = value; 41 } 42 } 43 44 // 2.定義雜湊表 45 private Map<Integer, DoubleLinkNode> cache = new HashMap<>(); 46 // 3.定義快取數量,快取容量 47 private int size; 48 private int capacity; 49 // 4.定義頭尾節點 50 private DoubleLinkNode head; 51 private DoubleLinkNode tail; 52 53 public Lru(int capacity) { 54 this.size = 0; 55 this.capacity = capacity; 56 // 設定偽頭部和尾部,非常巧妙 57 head = new DoubleLinkNode(); 58 tail = new DoubleLinkNode(); 59 head.next = tail; 60 tail.prev = head; 61 } 62 63 /** 64 * 將節點寫入頭部 65 * A-B-C,其中AC插入B,需要處理B的prv和next節點,C的prev,A的next 66 */ 67 private void addToHead(DoubleLinkNode node) { 68 node.prev = head; 69 node.next = head.next; 70 // 下面順序不可顛倒 71 head.next.prev = node; 72 head.next = node; 73 } 74 75 /** 76 * 刪除結點 77 * A-B-C,其中ABC刪除B,需要處理A的next和c的prev 78 */ 79 private void removeNode(DoubleLinkNode node) { 80 node.prev.next = node.next; 81 node.next.prev = node.prev; 82 } 83 84 /** 85 * 移動到頭結點 86 * A-B-C,其中AC插入B,需要處理B的prv和next節點,A的next,C的prev 87 */ 88 private void moveToHead(DoubleLinkNode node) { 89 removeNode(node); 90 addToHead(node); 91 } 92 93 /** 94 * 刪除尾結點 95 * @return DoubleLinkNode 96 */ 97 private DoubleLinkNode removeTail() { 98 DoubleLinkNode node = tail.prev; 99 removeNode(node); 100 return node; 101 } 102 103 /** 104 * 獲取快取值 105 * @param key 106 */ 107 public int get(int key) { 108 DoubleLinkNode node = cache.get(key); 109 if (node == null) { 110 return -1; 111 } else { 112 addToHead(node); 113 return node.value; 114 } 115 } 116 117 /** 118 * 儲存快取值 119 * @param key 120 */ 121 public void put(int key, int value) { 122 DoubleLinkNode node = cache.get(key); 123 // 如果節點存在 124 if (node != null) { 125 node.value = value; 126 moveToHead(node); 127 } else { 128 // 建立新節點,新增到hash表中 129 DoubleLinkNode newNode = new DoubleLinkNode(key, value); 130 cache.put(key, newNode); 131 // 移動到雙向連結串列頭部 132 moveToHead(newNode); 133 size++; 134 if (size > capacity) { 135 // hash表超出容量 136 DoubleLinkNode tail = removeTail(); 137 cache.remove(tail.key); 138 size--; 139 } 140 } 141 } 142 }