实现LFU中的set
和 get
样例
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
思路:利用List构建小顶堆,每次向缓存中添加内容时,调整堆的排序,使最近最访问次数多的在堆底,最近访问次数少的在堆顶。
1.添加元素时,如果key之前没访问过,访问次数为0,获取系统时间,否则访问次数+1
2.当缓存满时删除堆顶元素,向堆尾添加新的元素,向上调整堆。
3.获取元素,访问次数+1,获取系统时间
代码:
public class LFUCache {
private List<Node> cache = null;
//存放key在堆中的位置索引,如addr.get(2)=3,即key==2的元素在堆的索引为3
private Map<Integer, Integer> addr = new HashMap<Integer, Integer>();
private int capacity = 3;
public LFUCache(int capacity) {
cache = new ArrayList<Node>();
this.capacity = capacity;
}
public int get(int key) {
Integer node_index = addr.get(key);
Node node = null;
if (node_index == null) {
return -1;
}
node =cache.get(node_index);
node.accessCount++;
node.lastGetTime = System.nanoTime();
fixDown(node_index);
return node.value;
}
public void set(int key, int value) {
Integer node_index = addr.get(key);
Node node = null;
if (node_index != null) {
node = cache.get(node_index);
node.accessCount ++;
node.lastGetTime = System.nanoTime();
node.value = value;
fixDown(node_index);
return;
}else{
node = new Node();
node.value = value;
node.accessCount = 0;
node.key = key;
node.lastGetTime = System.nanoTime();
if(this.capacity == 0)return;
while (cache.size() >= this.capacity)
removeLast();
cache.add(node);
addr.put(key, cache.size()-1);
fixUp(cache.size()-1);
}
}
/**
* 向上调整,小值往上走,用于增加,往上调整不需要制定最上面的索引,肯定是0
*/
public void fixUp(int i){
int father = ( i - 1 )/2;
//当前节点比父节点小进行置换
while (i>0) {
if(cache.get(father).compareTo(cache.get(i))<=0){
break;
}else {
swap(father, i);
i = father;
father = (i-1)/2;
}
}
}
/**
*向下调整,顶端的大值往下调,主要用于删除和建堆,i表示要调整的节点索引,
* 删除时候,i是0,建堆时候i从最后一个节点的
* 父节点依次往下调整
*/
public void fixDown(int i){
int son = 0;
while (2*i+1<cache.size()){
//孩子节点
son = 2 * i +1;
//确保son是左右孩子中的最小者
if(son+1<cache.size()&&cache.get(son+1).compareTo(cache.get(son))<0)
son++;
//父节点大于孩子节点进行交换
if (cache.get(i).compareTo(cache.get(son))>0) {
swap(i, son);
i = son;
}else {
break;
}
}
}
/**
* 交换
* @param i
* @param j
*/
private void swap(int i ,int j){
Node temp = cache.get(i);
cache.set(i, cache.get(j));
cache.set(j, temp);
int ki= cache.get(i).key;
int kj = cache.get(j).key;
addr.put(ki, i);
addr.put(kj, j);
}
/**
* 淘汰最少使用的缓存
*/
private void removeLast() {
//底层代码是采用迭代器逐一比较
Node node = cache.get(0);
int key = node.key;
remove(key);
}
/**
* 删除堆中和Map中key的元素
* @param key
*/
public void remove(Integer key){
Integer pos = addr.get(key);
System.out.println(pos+"删除的位置");
if (pos == null)
return;
//将堆尾的元素放到pos位置
cache.set(pos, cache.get(cache.size()-1));
//记录堆中pos位置的元素在堆中位置
addr.put(cache.get(pos).key, pos);
//移除堆中最后一个元素
cache.remove(cache.size()-1);
//对进行调整
fixDown(pos);
//Map中也删除对应的key
addr.remove(key);
}
public class Node implements Comparable<Node>{
private Integer key;
public Integer value;
public Integer accessCount; //访问次数
public Long lastGetTime; //上次访问时间
//淘汰最近最少不访问的,访问次数不等时,返回比较结果,相等时比较访问时间
public int compareTo(Node o) {
int result = accessCount.compareTo(o.accessCount);
return result!=0?result:lastGetTime.compareTo(o.lastGetTime);
}
}
}