LRU緩存原理:
LRU(Least recently used,最近最少使用)算法根據數據的歷史訪問記錄來進行淘汰數據,其核心思想是“如果數據最近被訪問過,那麼將來被訪問的機率也更高”。
實現
最常見的實現是使用一個鏈表保存緩存數據,詳細算法實現如下:
- 新數據插入到鏈表頭部;
- 每當緩存命中(即緩存數據被訪問),則將數據移到鏈表頭部;
- 當鏈表滿的時候,將鏈表尾部的數據丟棄。
代碼
function Node(value, next) {
this.value = value;
this.next = next;
}
function LRUCache(initialCapacity, initialValue) {
this.size = 0;
this.head = null;
this.tail = null;
this.capacity = initialCapacity;
if (initialValue) {
var key = Object.keys(initialValue)[0];
//Object.keys()方法會返回一個由一個給定對象的自身可枚舉屬性組成的數組,數組中屬性名的排列順序和使用 for...in 循環遍歷該對象時返回的順序一致 (兩者的主要區別是 一個 for-in 循環還會枚舉其原型鏈上的屬性)。
var value = initialValue[key];
this.cache(key, value);
}
}
//是否爲空
LRUCache.prototype.isEmpty = function() {
return this.head == null && this.tail == null;
};
//在頭部做添加
LRUCache.prototype.addFirst = function(obj) {
var newNode = new Node(obj, null);
if (this.isEmpty()) {
this.head = this.tail = newNode;
} else {
this.head.next = newNode;
this.head = newNode;
//鏈表是反着的,head是最後一個節點
}
this.size++;
newNode = null;
};
//在尾部做刪除
LRUCache.prototype.removeLast = function() {
if (!this.isEmpty()) {
var key = Object.keys(this.tail.value)[0];
delete this[key];
this.tail = this.tail.next;
if (this.tail == null) {
this.head = null;
}
this.size--;
}
};
//將節點向頭部移動
LRUCache.prototype.moveForward = function(key) {
var node = this.search(key);
if (node && node.next) {
var next = node.next;
var temp = node.value;
node.value = next.value;
next.value = temp;
//位置交換了一下
}
};
//緩存元素
LRUCache.prototype.cache = function(key, value) {
//先查找是否已存在
var result = this.search(key);
//已存在採取覆蓋value策略
if (result) {
result.value[key] = value;
this[key] = value;
} else {
var obj = {};
obj[key] = value;
this.addFirst(obj);
var that = this;
Object.defineProperty(this, key, {
set : function(x) {
that.moveForward(key);
value = x;
},
get : function() {
that.moveForward(key);
return value;
},
configurable : true,
enumerable : true
});
//超出容量的話,將最少使用的刪除
if (this.size > this.capacity) {
this.removeLast();
}
}
//可以鏈式調用
return this;
};
//刪除元素
LRUCache.prototype.del = function(key) {
if (this.search(key)) {
var previous = null;
var cur = this.tail;
for (; cur; cur = cur.next) {
if (cur.value.hasOwnProperty(key)) {
break;
}
previous = cur;
}
if (previous) {
if (previous.next) {
//待定,感覺有點問題,刪除的是目標值的後一個節點
previous.next = previous.next.next;
this.size--;
}
} else {
this.tail = this.tail.next;
this.size--;
}
}
if (this.hasOwnProperty(key)) {
return (delete this[key]);
} else {
return (delete LRUCache.prototype[key]);
}
};
//查找元素
LRUCache.prototype.search = function(key) {
for (var e = this.tail; e; e = e.next) {
if (key in e.value) {
return e;
}
}
return null;
};
參考:
http://flychao88.iteye.com/blog/1977653
https://blog.csdn.net/esir82/article/details/72674274#commentBox