自己一次失敗的編碼= =
阿新 • • 發佈:2018-12-19
public class LFUCache { private final Node first; private final Node last; private final HashRep cache; private final HashMap<Integer,Node> count; LFUCache(int capacity){ cache = new HashRep(capacity); count = new HashMap<>(); first = new Node(0,0); first.count=-1; last = new Node(0,0); last.count=-1; first.next = last; last.pre = first; } /** * 首先,get並返回值 * 先從cache中get,如果為null,return -1 * 先看該節點在不在count中 * 如果在,刪除掉該count * count++ * 我們get一下這個++後的count值 * 如果有,move連結串列,設定count */ public int get(int key) { if (cache.capacity<1){ return -1; } Node thisNode = cache.get(key); if (thisNode==null){ return -1; } Node node = count.get(thisNode.count); if (node.key==thisNode.key){ if (thisNode.next.count==thisNode.count){ count.put(thisNode.count,thisNode.next); }else { count.remove(thisNode.count); } } thisNode.count++; Node nextNode = count.get(thisNode.count); if (nextNode!=null){ thisNode.move(nextNode); }else if (node.key!=thisNode.key){ thisNode.move(node); } count.put(thisNode.count,thisNode); return thisNode.val; } /** * 1.工具類比較智慧,new Node,直接put * 2.返回0,只是修改了值,不做處理 * 3.返回1,新增成功,需要把他 放在 count[0] 前面,並把count[0]改成新節點 * 4.返回-1.很難受,我們要先刪除最後一個節點 * cache 中刪掉 remove方法 * 節點.del()刪除連結串列中的引用關係 * 如果在count中,直接刪除,因為它本來就在連結串列尾,不可能存在與他相同count * 試圖放在count[0] 前面,如果count[0]為空就放在last前面,更新count[0] */ public void put(int key, int value) { if (cache.capacity<1){ return; } Node thisNode = new Node(key, value); int sign = cache.put(thisNode); if (sign == 0){ return; } if (sign==-1){ if (count.get(last.pre.count)==last.pre){ count.remove(last.pre.count); } cache.remove(last.pre.key); last.pre.del(); } Node nextNode = count.get(0); if (nextNode==null){ nextNode=last; } thisNode.move(nextNode); count.put(0,thisNode); } } /** * 這個類定義容器類,只維護節點的值,以及訪問次數 * 不能維護任何連結串列順序 * 實現LFU仍然需要一個對映來維護訪問次數對應連結串列的位置 * 我們也可使用該工具類來儲存對映 : 待定 */ class HashRep { final int capacity; private int size; private final int hashKey; private final Node[] rep; HashRep(int capacity) { this.capacity = capacity; size = 0; int n = capacity - 1; int p = 1; while (p < 17) { n |= n >>> p; p <<= 1; } hashKey = n; rep = new Node[hashKey + 1]; } /** * hash取index,迴圈取值,沒取到返回-1,取到返回值 * 不對count做操作 * 單純一個集合類 */ Node get(int key) { int index = key & hashKey; Node aimNode = rep[index]; while (aimNode != null && aimNode.key != key) { aimNode = aimNode.get; } return aimNode; } /** * 返回0 存在key更改數值 * 返回1 新增 * 返回-1 新增,但容量溢位 */ int put(Node node) { int key = node.key; int index = key & hashKey; //三種情況: 1.index位置上為null 2. 往後找,找到了key 3.沒有找到key相等的,取最後一個 Node aimNode = rep[index]; if (aimNode==null){ rep[index] = node; }else { if (aimNode.key==key){ aimNode.val = node.val; return 0; } while(aimNode.get!=null){ //找到了key,更改值 if (aimNode.key==key){ aimNode.val = node.val; return 0; } aimNode=aimNode.get; } aimNode.get = node; } size++; return size>capacity?-1:1; } /** * 如果在桶上面,桶下面沒節點 直接刪桶 size-- * 如果在桶上面,桶下面有節點,把桶下面那個移上來 size-- * 如果在桶下的節點之間,上面的get->這個的get size-- * 如果在桶末尾,上面那個節點指向這個節點的指標幹掉 size-- */ protected void remove(int key){ //一切為效能,不能遍歷兩邊連結串列 int index = key & hashKey; Node aimNode = rep[index]; if (aimNode==null){ return; } if (aimNode.key==key){ if (aimNode.get==null){ rep[index]=null; size--; }else{ rep[index] = aimNode.get; size--; } return; } //注意,單向連結串列使用get來對比 while(aimNode.get!=null&&aimNode.get.key!=key){ aimNode = aimNode.get; } //aimNode.get 有兩種情況 一種為null,一種為目標節點 if (aimNode.get!=null){ if (aimNode.get.get!=null){ aimNode.get = aimNode.get.get; }else { aimNode.get=null; } } } } class Node { Node pre; Node next; int key; int val; Node get; int count=0; Node(int key,int val){ this.key =key; this.val = val; } public void move(Node nextNode){ if(this.next!=null){ this.next.pre = this.pre; this.pre.next = this.next; } this.pre=nextNode.pre; this.next=nextNode; this.pre.next = this; nextNode.pre = this; } public void del(){ this.pre.next = next; this.next.pre = pre; } }
一些感想:
根據不同的需求選擇什麼樣的快取演算法,以及創新新的快取演算法是以後學習的一個方向
但目前還是先把眼前的問題解決,在寫較長的邏輯時總會有很多邏輯錯誤,發生錯誤總會加一些條件判斷來避免同類錯誤
但是錯誤多了之後會使程式碼很亂,沒有條理,更可怕的是加條件判斷的時候沒有經過思考,導致條件與邏輯衝突,加的判斷還有新的錯誤等等...以後寫東西一定將邏輯梳理完整再寫,爭取寫出來一次就過..