O(1)时间编程实现LFU算法

比起LRU算法,LFU算法就是多了一个优先级,LRU是最近最少使用淘汰,LFU是在使用次数最少的前提下淘汰最早的那个页面。为此跟上次一样,用一个 unordered_map  mkey,跟一个双向链表存储节点,不同的是我们需要加一个unordered_map mcount, mount【i】存储的是所有访问次数为i的最后一个节点。接下来就简单了,只要某个节点被访问,就令它的次数num加1,从原来的位置摘除,并插入到次数为num的地方。如果这里已经有次数为num 的节点,则插入到mcount【num】这地址的后面,如果不存在,就插入到原来的mcount【num-1】的后面,成为第一个次数为num的节点,具体看代码跟注释。

class LFUCache {
public:
	struct node {
		int key, val, count;;
		node* next;
		node* front;
		node() :key(0), val(0), count(0),next(NULL),front(NULL) {};
	};
	LFUCache(int capacity) {
		maxsize = capacity;
		head = new node();
		tail = new node();
		head->next = tail;
		tail->front = head;
		mcount[0] = head;
	}

    //获取页面
	int get(int key) {
		if (!mkey.count(key)) return -1;
		visied(mkey[key]);
		printf();
		return mkey[key].val;
	}

   //插入页面
	void put(int key, int value) {
		if (mkey.size() == maxsize)
			pop();
		mkey[key].key = key;
		mkey[key].val = value;
		visied(mkey[key]);		
		printf();
	}

    //节点被访问后,应该怎样维护链表
	void visied(node& n) {
		if (n.front)
			n.front->next = n.next;
		if (n.next)
			n.next->front = n.front;
        //如果节点已经在链表里,将它的前后两端连接,把节点暂时摘出来
		++n.count;          //访问次数加1
		if (&n == mcount[n.count - 1])
			mcount[n.count - 1] = n.front;//如果要被摘除的n正好是该数量的最后一个节点,则把
        //mcount[n.count - 1]记录的地址前移
		node* temp = NULL;
		if (mcount[n.count] != NULL)
			temp = mcount[n.count];
		else
			temp = mcount[n.count - 1];
        //如果数量为n.count的链表地址存在,则temp直接等于该地址指向的节点,如果不存在
        //则等于n.count-1的地址,这个地址一定存在。
		temp->next->front = &n;
		n.next = temp->next;
		temp->next = &n;
		n.front = temp;//把n插进去
		mcount[n.count] = &n;更新mcount[n.count]的地址
		if (mcount[n.count - 1]->count != n.count - 1) mcount[n.count - 1] = NULL;
        //如果mcount[n.count - 1]指向了它前面的节点,则令它等于0
	}

	void pop() {
		node* temp = head->next;
		head->next = temp->next;
		temp->next->front = head;    //准备删除头结点指向的节点,并使得头结点指向下一个节点
		if (temp->count != head->next->count)//证明要删除的节点是节点所在数量的最后一个
			mcount[temp->count] = NULL;
		mkey.erase(temp->key);
	}//弹出页面

	void printf() {
		node* p = head;
		while (p) {
			cout << p->val << " ";
			p = p->next;
		}
		cout << endl;
		p = tail;
		while (p) {
			cout << p->val << " ";
			p = p->front;
		}
		cout << endl << endl;
	}//打印存储的所有页面

private:
	unordered_map<int, node*> mcount;
	unordered_map<int, node> mkey;
	node* head;                  //总是指向使用次数最少,且最早的那个节点
	node* tail;
	int maxsize;
};

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值