lintcode算法题:LFUCache

问题描述:实现LFU中的get和set(LFU:least frequently used ,即最不经常使用页置换算法,要求在页置换时置换引用计数最小的页,因为经常使用的页应该有一个较大的引用次数。但是有些页在开始时使用次数很多,但以后就不再使用,这类页将会长时间留在内存中,因此可以将引用计数寄存器定时右移一位,形成指数衰减的平均使用次数。--百度 -_-|||)

样例:缓存大小为3(capacity =3)

set(2,2)
set(1,1)
get(2)
>> 2
get(1)
>> 1
get(2)
>> 2
set(3,3)
set(4,4)
get(3)
>> -1
get(2)
>> 2
get(1)
>> 1
get(4)
>> 4

我的实现思路:

1.Map用来存储缓存

2.使用双向链表来标记移除顺序。

   将使用次数最少元素中的访问时间最早的哪一个放到链表尾部,作为下一个删除对象。

   每次set(新加入)数据时,检查map大小等于capacity值时,从map中删除数据(根据链表尾部数据的key),并将链表尾部替换为新数据。

   每次set(更新)数据时,直接更新map中的数据,并跟新数据的时间标记和使用频次

   然后,将set的数据在链表中向前重新排序(当链表前一元素的使用频次低于本数据或者频次相等但是时间标记早于本元素时,将此两元素交换位置)

  每次get数据时,更新数据的使用频次和时间标记,并在此执行链表中该元素的重新排序

上代码(提交给lintcode后,发现还有其他的更优的实现。。。还没有细看)

public class LFUCache {
    /*
     * @param capacity: An integer
     */
    private Map<Integer, CacheItem> map = new HashMap<>();
    private CacheItem footNode;
    private int capacity;
    private long cnt=Long.MIN_VALUE;

    public LFUCache(int capacity) {
        // do intialization if necessary
        this.capacity=capacity;
    }

    /*
     * @param key: An integer
     * @param value: An integer
     * @return: nothing
     */
    public void set(int key, int value) {
        // write your code here
        CacheItem item;
        if(map.containsKey(key)) {
            item=map.get(key);
            item.value=value;
            item.update_time=cnt++;
            item.frecquece++;
        } else {
            CacheItem newItem = new CacheItem();
            newItem.value=value;
            newItem.key=key;
            newItem.update_time = cnt++;
            if(map.size() == capacity){
                map.remove(footNode.key);
                footNode = footNode.before;
            }
            newItem.before=footNode;
            if(footNode != null) {
                footNode.next = newItem;
            }
            footNode=newItem;
            item=newItem;
        }
        resortBefore(item);
        map.put(key,item);
    }

    /*
     * @param key: An integer
     * @return: An integer
     */
    public int get(int key) {
        // write your code here
        if(!map.containsKey(key)) return -1;
        CacheItem item = map.get(key);
        int value=item.value;
        item.frecquece++;
        item.update_time=cnt++;
        resortBefore(item);
        return value;
    }

    private void resortBefore(CacheItem item){
        if(item.before != null && (item.frecquece > item.before.frecquece || (item.frecquece == item.before.frecquece && item.update_time >= item.before.update_time))){
            CacheItem swap = item.before;
            CacheItem swapbefore = item.before.before;
            CacheItem swapafter = item.next;
            if(swapbefore != null) {
                swapbefore.next = item;
            }
            item.before = swapbefore;
            swap.before = item;
            swap.next = swapafter;
            if(swapafter != null) {
                swapafter.before=swap;
            }else{
                footNode=swap;
            }
            item.next = swap;
            resortBefore(item);
        }
    }


    private static class CacheItem {
        CacheItem before;
        CacheItem next;
        int key;
        int value;
        long update_time;
        int frecquece;
    }
}

代码比较简单,没有写注释。。。(这题在lintcode中居然是【困难】级,很多【简单】级的反而感觉无法下手 -_-|||)

转载于:https://my.oschina.net/yangboxu/blog/1800124

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值