面试题:手写一个LRU看看

2020/4/1 更新

昨晚做了一下携程的19年笔试题,遇到了LRU。今天有一场携程的笔试,晚上等笔试完来更新一下对LRU的讨论。

LRU https://www.cnblogs.com/NickyYe/p/4460239.html

https://my.oschina.net/u/1540325/blog/603413

首先,什么是LRU?(解释摘自百度)

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

常见的可以用Java自带的LinkedHashMap,LinkedList(或者ArrayDeque)和数组实现。

作为一道常见的面试题,记录一下这几种解法。

  • LinkedHashMap,是一种有序的Map,它可以按照插入顺序或者访问顺序进行排序。而TreeMap,是按照键的自然排序或者自定义排序来进行排序。为了实现LRU,采用访问顺序的LinkedHashMap,LinkedHashMap提供了一个钩子方法,在新插入元素后可以决定是否删除最老的元素。
public class LRUcache<K,V> extends LinkedHashMap<K, V> {
    private int capacity;
    LRUcache(int capacity){
        super(capacity+1,1.0f,true);
        //调用父类的构造方法,初始化时指定
        // capacity最大容量,
        // loadfactor装载因子,
        //accessOrder 是否按访问排序,默认是false
        this.capacity=capacity;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size()>this.capacity;
    }
}
  • 使用LinkedList(或者ArrayDeque)和HashSet实现,这里其实LinkedList(或者ArrayDeque)是自带contains()函数的,但是时间复杂度为O(n),因此使用HashSet将查找时间复杂度降为O(1)。这里还要特别注意的一点是LinkedList和ArrayDeque的remove方法的区别。

在ArrayDeque中,

public boolean remove(Object o) {
        return removeFirstOccurrence(o);
    }

在LinkedList中,remove方法进行了重载,在实现LRU过程中remove时记得使用remove(new Integer(n))而不是remove(n),

public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }


public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

下面看实现的代码。

public class LRUcache2 {
    private LinkedList<Integer> cacheList = new LinkedList<Integer>();
    private HashSet<Integer> set =new HashSet<>();

    private int capacity;
    LRUcache2(int capacity){
        this.capacity=capacity;
    }

    private boolean isQueueFull(){
        return cacheList.size()==capacity;
    }
    //入队函数
    public void enqueue(int n){
        if(isQueueFull()){
            Integer removePage = cacheList.removeLast();
            set.remove(removePage);
        }
        cacheList.addFirst(n);
        set.add(n);
    }
    //当某个页被访问到时
    public void accessPage(int n){
        //不在缓存中则入队
       if(!set.contains(n)){
           enqueue(n);
       }
       //在缓存中,检查是否在队头,不在则移除元素并添加到队头
       else if(!cacheList.getFirst().equals(n))
       {
           cacheList.remove(new Integer(n));
           cacheList.addFirst(n);
       }
    }
    public static void main(String[] args) {
        LRUcache2 lru =new LRUcache2(3);
        lru.accessPage(1);
        lru.accessPage(2);
        lru.accessPage(5);
        lru.accessPage(1);
        lru.accessPage(6);
        lru.accessPage(7);
        System.out.println();//断点调试 结果7,6,1
    }
}
  • 数组实现,有时间再写吧.....
发布了24 篇原创文章 · 获赞 3 · 访问量 1301

猜你喜欢

转载自blog.csdn.net/qinian_ztc/article/details/105156345