cache 清除算法 LRU & LFU & FIFO

LRU:

LinkedHashMap ,

实现思路:HashMap + 双向链表环

按照最近访问/插入顺序,始终保持队列尾部的为最近访问或者最近插入的数据,删除从对头开始!

LinkedHashMap扩展如下方法即可:

 

protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

 

 

LFU:

实现思路:HashMap + PriorityQueue

下面是个根据Key的自然数据排序的案例(类似,可以把Key包装成一个可排序的包装类型,根据访问次数确定顺序):

 

import java.util.HashMap;
import java.util.PriorityQueue;

/**
 * 
 * @author xinchun.wang
 * @email: 532002108@qq.com
 */
public class LFUHashMap<K, V> {

	private static final int max_size = 10;

	HashMap<K, V> map = new HashMap<K, V>();

	PriorityQueue<Node<K>> tSet = new PriorityQueue<Node<K>>();

	@SuppressWarnings("unchecked")
	public V put(K key, V value) {
		if (map.size() > max_size) {
			Node<K> firstKey = (Node<K>) tSet.poll();
			map.remove(firstKey.getKey());
		}
		tSet.add(new Node(key, 1));
		return map.put(key, value);
	}

	public V get(Object key) {
		V result = map.get(key);
		incHit(key);
		return result;
	}

	private void incHit(Object key) {
		for (Object item : tSet) {
			if (((Node) item).key == key) {
				((Node) item).setCount(((Node) item).getCount() + 1);
				break;
			}
		}
	}

	@Override
	public String toString() {
		return map.toString();
	}

	public static void main(String[] args) {
		LFUHashMap<Integer, String> lfu = new LFUHashMap<Integer, String>();
		for (int i = 0; i < 100; i++) {
			lfu.put(i, String.valueOf(i) + "_data");
			if (i > 5) {
				lfu.get(1);
				lfu.get(2);
				lfu.get(3);
				lfu.get(4);
			}
			if (i > 10) {
				lfu.get(9);
			}
		}
		while (lfu.tSet.peek() != null) {
			System.out.println(lfu.tSet.poll());
		}
		System.out.println(lfu);
	}

	private static class Node<K> implements Comparable<Node<K>> {
		private K key;
		private int count;

		public Node(K key, int count) {
			this.key = key;
			this.count = count;
		}

		public K getKey() {
			return key;
		}

		public int getCount() {
			return count;
		}

		public void setCount(int count) {
			this.count = count;
		}

		@Override
		public String toString() {
			return "Node [key=" + key + ", count=" + count + "]";
		}

		@Override
		public int compareTo(Node<K> o) {
			int diff = this.count - o.count;
			return diff != 0 ? diff : -((Integer) o.key).compareTo((Integer) this.key);
		}

	}

}

 

 

FIFO:

仿照LinkedHashMap,通过LinkedList 就可以实现FIFO的元素排队

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: LFU算法代码: ``` class LFUCache { public: LFUCache(int capacity) { cap = capacity; minFreq = ; } int get(int key) { if (cache.count(key) == ) { return -1; } freq[cache[key].second].erase(iter[key]); cache[key].second++; freq[cache[key].second].push_back(key); iter[key] = --freq[cache[key].second].end(); if (freq[minFreq].size() == ) { minFreq++; } return cache[key].first; } void put(int key, int value) { if (cap <= ) { return; } if (get(key) != -1) { cache[key].first = value; return; } if (cache.size() >= cap) { cache.erase(freq[minFreq].front()); iter.erase(freq[minFreq].front()); freq[minFreq].pop_front(); } cache[key] = {value, 1}; freq[1].push_back(key); iter[key] = --freq[1].end(); minFreq = 1; } private: int cap, minFreq; unordered_map<int, pair<int, int>> cache; unordered_map<int, list<int>> freq; unordered_map<int, list<int>::iterator> iter; }; ``` LRU算法代码: ``` class LRUCache { public: LRUCache(int capacity) { cap = capacity; } int get(int key) { if (cache.count(key) == ) { return -1; } auto it = cache[key]; int val = it->second; lru.erase(it); lru.push_front({key, val}); cache[key] = lru.begin(); return val; } void put(int key, int value) { if (cap <= ) { return; } if (get(key) != -1) { cache[key]->second = value; return; } if (cache.size() >= cap) { int delKey = lru.back().first; lru.pop_back(); cache.erase(delKey); } lru.push_front({key, value}); cache[key] = lru.begin(); } private: int cap; list<pair<int, int>> lru; unordered_map<int, list<pair<int, int>>::iterator> cache; }; ``` FIFO算法代码: ``` class FIFOCache { public: FIFOCache(int capacity) { cap = capacity; } int get(int key) { if (cache.count(key) == ) { return -1; } return cache[key]; } void put(int key, int value) { if (cap <= ) { return; } if (cache.size() >= cap && cache.count(key) == ) { int delKey = fifo.front(); fifo.pop(); cache.erase(delKey); } if (cache.count(key) == ) { fifo.push(key); } cache[key] = value; } private: int cap; queue<int> fifo; unordered_map<int, int> cache; }; ``` ### 回答2: 页面置换算法是操作系统中用于管理内存的一种重要策略,在不足内存的情况下将内存中不常用的页面暂时保存到辅助存储器中,从而保证计算机的正常运行。在实际的操作系统中,有许多不同的页面置换算法,其中比较常用的有LFULRUFIFO算法。 其中,LFU(Least Frequently Used)算法是根据页面的历史使用次数来选择将哪一个页面换出内存。在使用过程中,每个页面都有一个使用计数器,每次访问该页面时就会将计数器的值增加。当需要淘汰一个页面时,就选择使用次数最少的那个页面换出内存。 LRU(Least Recently Used)算法,则是根据页面上次使用的时间来选择淘汰哪一个页面,即淘汰最长时间未被访问的页面。在实现中,可以使用链表或者栈来存储页面的访问时间,每次访问页面时,就将该页面移到链表或者栈的顶部。当需要淘汰页面时,就选择最底部的那个页面。 FIFO(First In First Out)算法则是根据页面进入内存的顺序来选择淘汰那一个页面。在使用过程中,每个页面都有一个进入时间,当需要淘汰一个页面时,就选择最早进入内存的那个页面进行淘汰。 这些算法都有其特点和优缺点,实际使用时需要根据不同的场景选择合适的算法。例如,LFU算法适用于对访问次数进行较为敏感的场景,LRU算法适用于需要保证近期访问页面能够被频繁使用的场景,FIFO算法适用于对访问顺序较为敏感的场景。 以下是三种算法的示例代码: LFU算法: ``` void lfu_replace(int *mem, int *usage, int num_pages, int curr_page) { int min = usage[0], min_idx = 0; for (int i = 1; i < num_pages; i++) { if (usage[i] < min) { min = usage[i]; min_idx = i; } } mem[min_idx] = curr_page; usage[min_idx] = 1; } ``` LRU算法: ``` void lru_replace(int *mem, int num_pages, int curr_page) { int i, j, min; for (i = 0; i < num_pages; i++) { if (mem[i] == curr_page) { break; } } if (i == num_pages) { // 页面不在内存中 for (i = 0, min = mem[0], j = 0; j < num_pages; j++) { if (mem[j] < min) { min = mem[j]; i = j; } } mem[i] = curr_page; // 替换最久未使用的页面 } } ``` FIFO算法: ``` void fifo_replace(int *mem, int num_pages, int curr_page, int *start_idx) { int i; if (mem[*start_idx] == -1) { // 内存未满 mem[*start_idx] = curr_page; (*start_idx)++; } else { // 根据页面进入内存的顺序替换页面 mem[*start_idx] = curr_page; (*start_idx) = ((*start_idx) + 1) % num_pages; } } ``` ### 回答3: 页面置换算法是内存管理中的重要概念,它决定了当物理内存不足时应该把哪些页面置换出去。通常情况下,操作系统会根据一定策略选择要置换的页面,而其中最常用的三种算法就是LFU(最不经常使用)、LRU(最近最少使用)和FIFO(先进先出)。 LFU算法的实现代码如下: ``` 1. 扫描内存中所有页面的访问频率 2. 找到访问频率最低的页面,选择该页面作为要置换出去的页面 3. 如果有多个页面访问频率一样,从它们中选择最长时间未访问的页面作为被置换页面 ``` LFU算法是一个比较优秀的页面置换算法,在保证页面缓存高命中率的同时,能够剔除那些不常用的页面,从而使得空间利用更为有效。不过,LFU算法的缺点是需要定期扫描内存中的页面,这会占用一定的CPU资源。 LRU算法的实现代码如下: ``` 1. 维护一个链表,每当一个页面被访问,就将该页面移动到链表的最前端 2. 当内存不足时,选择链表尾部的页面进行置换 ``` LRU算法是一种比较优秀的算法,它能够选择一定时间段内未被访问的页面进行缓存置换,从而保证空间的有效利用。不过,LRU算法需要维护一个链表结构,每个页面都需要记录它的访问时间戳,这会占用内存空间。 FIFO算法的实现代码如下: ``` 1. 将新页面按照先进先出的原则加入内存 2. 当内存不足时,选择最早加入内存的页面置换出去 ``` FIFO算法是一种较为简单的算法,不需要记录访问频率和时间戳等信息,只需要实现一个队列即可。不过,FIFO算法容易发生“抖动”现象,也就是不断地换入换出同一个页面,从而降低了命中率。除此之外,FIFO算法也不够智能化,没有考虑到未来的缓存需求,只是进行简单的先进先出的选择置换。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值