利用HashMap和双向链表实现LRU(最近最久未被使用)算法
一个场景,缓存机制,(用双向链表维护缓存区域,头节点为最久未被访问节点,尾节点为最近被访问的节点),缓存有限,优先替换出头节点,最近被访问的放到尾节点。
HashMap的作用:链表删除添加节点的时间复杂度为O(1),但是找到元素的时间复杂度为O(n),通过HashMap实现O(1)复杂度的节点查找。
不过多解释了,直接上代码了,不懂可以直接留言。
class LRUCache {
HashMap<Integer, Node> hashMap;
int capacity = 0;
Node head = null;
Node tile = null;
public LRUCache(int capacity) {
hashMap = new HashMap();
this.capacity = capacity;
}
public int get(int key) {
if (hashMap.containsKey(key)) {
Node node = hashMap.get(key);
moveToTile(node);
return node.value;
}
return -1;
}
public void put(int key, int value) {
//先看HashMap是否存在
if (hashMap.containsKey(key)) {
Node node = hashMap.get(key);
node.value = value;
moveToTile(node);
}else {
//hashmap里面不存在的话,如果尾巴节点为空,则构造头节点和尾节点
if (tile == null) {
head = tile = new Node(null, null, key, value);
hashMap.put(key, head);
}else {
//如果尾巴节点不为空,直接在尾部追加,
//不要忘记,假如已经达到最大容量,则需要去掉头节点
removeEldest();
Node node = new Node(tile, null, key, value);
tile.next = node;
tile = node;
hashMap.put(key, node);
}
}
}
//把一个节点移动到链表尾巴
public void moveToTile (Node node) {
if (node == tile) return;
if (node == head) {
head = head.next;
head.pre = null;
tile.next = node;
node.pre = tile;
node.next = null;
tile = node;
}else {
node.pre.next = node.next;
node.next.pre = node.pre;
tile.next = node;
node.pre = tile;
node.next = null;
tile = node;
}
}
//移除最老的节点,即头节点
public void removeEldest () {
if (hashMap.size() == capacity) {
hashMap.remove(head.key);
Node node = head;
head = head.next;
if (head != null) head.pre = null;
node.next = null;
}
}
class Node {
Node pre;
Node next;
int key;
int value;
public Node () {}
public Node(Node pre, Node next, int key, int value) {
this.pre = pre;
this.next = next;
this.key = key;
this.value = value;
}
}
}
下面的不用啊看了,因为是之前写的,可能比较乱,上面的比较清楚!
public class DoubleLinkedList implements Iterable<Integer>{
private Node first;
private Node head;
private Node tile;
private int maxValue;
private int size;
private HashMap<Integer,Node> hashMap;
public DoubleLinkedList(int maxValue){
this.first = new Node(0);
this.head = null;
this.tile = null;
this.maxValue = maxValue;
this.size = 0;
this.hashMap = new HashMap<Integer, Node>();
}
public int size(){
return size;
}
public void put(int value){
Node node = new Node(value);
if (size==0){
first.next = node;
node.pre = first;
head = node;
tile = node;
hashMap.put(value,node);
size++;
}else{
//缓存中已经存在该value
if(get(value) != -1){
Node node1 = hashMap.get(value);
if(tile != node1){
//摘除 放到尾巴
Node before = node1.pre;
Node after = node1.next;
before.next = after;
after.pre = before;
tile.next = node1;
node1.pre = tile;
//下面这步很重要 一定要将next置空 不然会出现循环指针
node1.next = null;
tile = node1;
}
}
//缓存中不存在该value
else {
//缓存已经满了
if(size == maxValue){
//去掉头节点
//并且从hashMap中除去
hashMap.remove(head.value);
Node node2 = head.next;
first.next = node2;
node2.pre = first;
head = node2;
//元素放到尾节点
tile.next = node;
node.pre = tile;
tile = node;
}
//缓存没有满
else {
//直接放到为节点
tile.next = node;
node.pre = tile;
tile = node;
size++;
}
//放到hashmap中
hashMap.put(value,node);
}
}
}
public int get(int value){
if(hashMap.containsKey(value)){
return value;
}
return -1;
}
public Iterator<Integer> iterator() {
return new DoubleIterator();
}
private class DoubleIterator implements Iterator<Integer>{
Node node = first;
private DoubleIterator(){
}
public boolean hasNext() {
if(node.next != null){
return true;
}
return false;
}
public Integer next() {
node = node.next;
return node.value;
}
public void remove() {
}
}
private class Node{
private Node pre;
private Node next;
private int value;
private Node(int value){
this.value = value;
this.pre = null;
this.next = null;
}
}
}