先進先出,如果快取容量滿,則優先移出最早加入快取的資料;其內部可以使用佇列實現。1)object get(key):獲取儲存的資料,如果資料不存在或者已經過期,則返回null。
2)void put(key,value,expiretime):加入快取,無論此key是否已存在,均作為新key處理(移除舊key);如果空間不足,則移除已過期的key,如果沒有,則移除最早加入快取的key。過期時間未指定,則表示永不自動過期。
3)此題需要注意,我們允許key是有過期時間的,這一點與普通的fifo有所區別,所以在設計此題時需要注意。(也是面試考察點,此題偏設計而非演算法)
普通的fifo或許大家都能很簡單的寫出,此處增加了過期時間的特性,所以在設計時需要多考慮。如下示例,為fifo的簡易設計,尚未考慮併發環境場景。
1)用普通的hashmap儲存快取資料。
2)我們需要額外的map用來儲存key的過期特性,例子中使用了treemap,將「剩餘存活時間」作為key,利用treemap的排序特性。
public class fifocache
public object get(string key)
//如果不包含過期時間
long expired = value.expired;
long now = system.nanotime();
//已過期
if (expired > 0 && expired <= now)
return value.value;
} public void put(string key,object value)
public void put(string key,object value,int seconds)
//一次移除所有過期key
string _value = expired.get(_key);
cache.remove(_value);
iterator.remove();
} }
//如果仍然容量不足,則移除最早訪問的資料
if (capacity < cache.size())
iterator.remove();
} }
//如果此key已存在,移除舊資料
value current = cache.remove(key);
if (current != null && current.expired > 0)
//如果指定了過期時間
if(seconds > 0) else
} private long expiredtime(int expired)
public void remove(string key)
long expired = value.expired;
if (expired > 0)
} class value
} }
least recently used,最近最少使用,是目前最常用的快取演算法和設計方案之一,其移除策略為「當快取(頁)滿時,優先移除最近最久未使用的資料」,優點是易於設計和使用,適用場景廣泛。演算法可以參考leetcode 146 (lru cache)。1)object get(key):從canche中獲取key對應的資料,如果此key已過期,移除此key,並則返回null。
2)void put(key,value,expired):設定k-v,如果容量不足,則根據lru置換演算法移除「最久未被使用的key」,需要注意,根據lru優先移除已過期的keys,如果沒有,則根據lru移除未過期的key。如果未設定過期時間,則認為永不自動過期。
3)此題,設計關鍵是過期時間特性,這與常規的lru有所不同。畢竟「過期時間」特性在cache設計中是必要的。
1)lru的基礎演算法,需要了解;每次put、get時需要更新key對應的訪問時間,我們需要乙個資料結構能夠儲存key最近的訪問時間且能夠排序。
2)既然包含過期時間特性,那麼帶有過期時間的key需要額外的資料結構儲存。
3)暫時不考慮併發操作;盡量兼顧空間複雜度和時間複雜度。
4)此題仍然偏向於設計題,而非純粹的演算法題。
此題**與fifo基本相同,唯一不同點為get()方法,對於lru而言,get方法需要重設訪問時間(即調整所在cache中順序)
public object get(string key)
//如果不包含過期時間
long expired = value.expired;
long now = system.nanotime();
//已過期
if (expired > 0 && expired <= now)
//相對於fifo,增加順序重置
cache.remove(key);
cache.put(key,value);
return value.value;
} 複製**lfu
最近最不常用,當快取容量滿時,移除訪問次數最少的元素,如果訪問次數相同的元素有多個,則移除最久訪問的那個。設計要求參見leetcode 460( lfu cache)
public class lfucache
public object get(string key)
touch(key);
return keytovalue.get(key);
} /**
* 如果乙個key被訪問,應該將其訪問次數調整。
* @param key
*/
private void touch(string key)
//然後將此key的統計資訊加入到管理列表中
linkedhashsetcountkeys = counttolrukeys.get(count + 1);
if (countkeys == null)
countkeys.add(key);
} public void put(string key, object value)
if (keytovalue.containskey(key))
//容量超額之後,移除訪問次數最少的元素
if (keytovalue.size() >= capacity)
keytocount.remove(evictkey);
keytovalue.remove(evictkey);
} keytovalue.put(key, value);
keytocount.put(key, 1);
linkedhashsetkeys = counttolrukeys.get(1);
if (keys == null)
keys.add(key);
} }
FIFO LRU LFU三種快取演算法
先進先出,如果快取容量滿,則優先移出最早加入快取的資料 其內部可以使用佇列實現。1 object get key 獲取儲存的資料,如果資料不存在或者已經過期,則返回null。2 void put key,value,expiretime 加入快取,無論此key是否已存在,均作為新key處理 移除舊k...
FIFO LRU LFU三種演算法
提到快取,有兩點是必須要考慮的 1 快取資料和目標資料的一致性問題。2 快取的過期策略 機制 其中,快取的過期策略涉及淘汰演算法。常用的淘汰演算法有下面幾種 1 fifo firstin first out 先進先出 2 lru leastrecently used 最近最少使用 3 lfu lea...
三種快取模式(Cache Pattern)
cup和記憶體資料交換的效率不高,這是指令流水線式處理器的瓶頸之一。我們可以通過儲存層次 memory hierarchy 的方式來解決這個問題。這個儲存層次內有 1 容量小的 高速的快取 2 容量較大的 慢一點記憶體 3 容量很大的 但很慢的硬碟 2 檢查記憶體 main memory 如果a在主...