【问题标题】:LRU-2 implementationLRU-2 实施
【发布时间】:2015-07-22 02:36:07
【问题描述】:

我正在尝试用 Java 中的 PriorityQueue 实现 LRU-2 缓存。在我看来,我可以在O(LogN) 时间内完成poll()add(),但是要在缓存中搜索,我会花费O(N) 时间。关于如何在O(LogN) 时间内使用poll()add()search() 实现LRU-2 缓存的任何建议?还是根本不可能这样做?

【问题讨论】:

  • 我必须分析 LRU-2,但大多数缓存都是带有辅助结构的哈希表,例如横切条目以对其进行排序的队列。许多使用双向链表(例如 LRU),因此所有操作都是 O(1)。
  • DoubleLinkedList 在 LRU-2 的情况下不起作用。我正在考虑使用哈希表和红黑树,以便所有操作都在 O(log N) 中。但我仍然想知道是否存在更好的解决方案。
  • 您可以调整O(1) LFU 方法。附言如果您可以分享您的最终结果,那就太好了,因为我开始为我的缓存库刷新simulator
  • 一个 maxHeap 和 hashtable 可以工作。在最坏的情况下,所有操作都需要 O(logN) 时间。谢谢你。完成后我会分享。谢谢。
  • O(1) LFU 方法不起作用。

标签: algorithm caching data-structures lru


【解决方案1】:

经过一番挣扎,我得到了一个带有 MaxHeap 和 HashMap 的 LRU-2,操作最多需要 O(log N) 时间。这是 Java 中 LRU-2 的代码。代码也在我的GitHub

Node.java,这是HashMap和MaxHeap中的值

package me.york;

class Node<K, V extends Comparable<V>> implements Comparable<Node<K, V>> {
private K key;
private V value;
private int index;
private long lastTime;
private long lastSecondTime;
public static long INIT = -1;

Node(K key, V value) {
    this.key = key;
    this.value = value;
    lastTime = INIT;
    lastSecondTime = INIT;
}

@Override
public int compareTo(Node<K, V> o) {
    return (int)(lastSecondTime-o.getLastSecondTime());
}

K getKey() {
    return key;
}

V getValue() {
    return value;
}

int getIndex() {
    return index;
}

void setIndex(int index) {
    this.index = index;
}

long getLastTime() {
    return lastTime;
}

void setLastTime(long lastTime) {
    this.lastTime = lastTime;
}

long getLastSecondTime() {
    return lastSecondTime;
}

void setLastSecondTime(long lastSecondTime) {
    this.lastSecondTime = lastSecondTime;
}
}

MaxHeap.java,LRU-2算法的主要逻辑在这个类中。

package me.york;

class MaxHeap<K, V extends Comparable<V>> {
private Node<K, V>[] heap;
private int currentSize;
private long count;

MaxHeap(int size) {
    count = 0;
    currentSize = 1;
    heap = new Node[size + 1];
}

boolean isFull() {
    return currentSize >= heap.length;
}

Node<K, V> add(Node<K, V> value) {
    Node<K, V> previous = value;
    if (currentSize >= heap.length) {
        previous = removeMax();
    }
    if (value.getLastSecondTime() != Node.INIT) {
        value.setLastSecondTime(value.getLastTime());
    } else {
        value.setLastSecondTime(count);
    }
    value.setLastTime(count++);
    value.setIndex(currentSize);
    heap[currentSize++] = value;
    siftUp(currentSize - 1);
    return previous;
}

Node<K, V> getMax() {
    return heap[0];
}

Node<K, V> removeMax() {
    return remove(0);
}

Node<K, V> reVisited(int index) {
    Node<K, V> node = heap[index];
    remove(node.getIndex());
    add(node);
    return node;
}

Node<K, V> remove(int index) {
    Node<K, V> previous = heap[index];
    heap[index] = heap[--currentSize];
    siftDown(index);
    return previous;
}

private void siftDown(int index) {
    int left = 2 * index;
    int right = 2 * index + 1;
    int largest;
    if (left < currentSize && heap[left].compareTo(heap[index]) > 0)
        largest = left;
    else
        largest = index;
    if (right < currentSize && heap[right].compareTo(heap[largest]) > 0)
        largest = right;
    if (largest != index) {
        Node<K, V> temp = heap[index];
        heap[index] = heap[largest];
        heap[largest] = temp;
        heap[index].setIndex(largest);
        heap[largest].setIndex(index);
        siftDown(largest);
    }
}

private void siftUp(int index) {
    while (index > 1 && heap[index].compareTo(heap[index / 2]) > 0) {
        Node<K, V> temp = heap[index];
        heap[index] = heap[index / 2];
        heap[index / 2] = temp;
        heap[index].setIndex(index / 2);
        heap[index / 2].setIndex(index);
        index = index / 2;
    }
}
}

LRU2Cache.java,这是LRU-2缓存算法的入口。它只是提供了两个函数,get() 和 put()。

package me.york;

import java.util.HashMap;
import java.util.Map;

public class LRU2Cache<K, V extends Comparable<V>> {
private MaxHeap<K, V> maxHeap;
private Map<K, Node<K, V>> map;

public LRU2Cache(int cacheSize) {
    maxHeap = new MaxHeap<K, V>(cacheSize);
    map = new HashMap<K, Node<K, V>>((int) ((float) cacheSize / 0.75F + 1.0F));
}

public void put(K key, V value) {
    if (key != null && value != null) {
        Node<K, V> previous;
        if ((previous = map.get(key)) != null) {
            maxHeap.remove(previous.getIndex());
        }
        if (maxHeap.isFull())
            map.remove(maxHeap.getMax().getKey());
        previous = new Node<K, V>(key, value);
        map.put(key, previous);
        maxHeap.add(previous);
    }
}

public V get(K key) {
    V value = null;
    if (key != null) {
        Node<K, V> node = map.get(key);
        if (node != null) {
            value = node.getValue();
            maxHeap.reVisited(node.getIndex());
        }
    }
    return value;
}
}

【讨论】:

  • 您似乎忘记从哈希图中逐出。
  • 哦,compareTo 总是返回零,这将使堆无效。
  • 驱逐似乎没有使用访问时间,所以我的理解是这是一个有界的SortedMap,它删除了最后一个条目,其中的顺序奇怪地由值定义。
  • 感谢您的关注。最大项应该是数组中的第一项,例如。堆[0]。谢谢。
  • 我认为你可以使用 Java 的 TreeMap 而不是你的堆,比较器在时间 2 (如果设置),否则在时间 1。我很确定你可以使用 O(1) LFU 技巧(参见我对一个 here 的快速破解)。如果您有兴趣比较命中率,我可以将其移植到我的模拟器中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-09
  • 1970-01-01
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多