package NC;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
 * NC93 设计LRU缓存结构
 *
 * 设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 k,并有如下两个功能
 * 1. set(key, value):将记录(key, value)插入该结构
 * 2. get(key):返回key对应的value值
 *
 * 提示:
 * 1.某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的,然后都会刷新缓存。
 * 2.当缓存的大小超过k时,移除最不经常使用的记录。
 * 3.输入一个二维数组与k,二维数组每一维有2个或者3个数字,第1个数字为opt,第2,3个数字为key,value
 * 若opt=1,接下来两个整数key, value,表示set(key, value)
 * 若opt=2,接下来一个整数key,表示get(key),若key未出现过或已被移除,则返回-1
 * 对于每个opt=2,输出一个答案
 * 4.为了方便区分缓存里key与value,下面说明的缓存里key用""号包裹
 *
 * @author Tang
 * @date 2021/9/24
 */
public class LRU {
    public int[] LRU (int[][] operators, int k) {
        // write code here
        List<Object> result = new ArrayList<>();
        LinkedMap linkedMap = new LinkedMap(k);
        for(int i = 0; i < operators.length; i++) {
            int[] operator = operators[i];
            if(operator[0] == 2) {
                Object o = linkedMap.get(operator[1]);
                result.add(o == null ? -1 : o);
            }else {
                linkedMap.put(operator[1], operator[2]);
            }
        }
        int[] results = new int[result.size()];
        for(int i = 0; i < result.size(); i++) {
            results[i] = (int) result.get(i);
        }
        return results;
    }
    public static void main(String[] args) {
        LinkedMap linkedMap = new LinkedMap(3);
        linkedMap.put(3,3);
        linkedMap.put(1,1);
        linkedMap.put(2,2);
        linkedMap.put(3,4);
        linkedMap.put(5,5);
        linkedMap.put(6,6);
        linkedMap.put(7,7);
        System.out.println(linkedMap.size());
        System.out.println(linkedMap.get(7));
        int[][] num = {{1,1,1},{1,2,2},{1,3,2},{2,1},{1,4,4},{2,2}};
        new LRU().LRU(num, 3);
    }
}
class LinkedMap {
    /**
     * 首元素 不用做存储数据
     */
    Entry first = new Entry(null,null);
    Entry last;
    int size;
    int max;
    public LinkedMap(int max) {
        this.max = max;
    }
    public int size() {
        return size;
    }
    private Entry search(Object key) {
        //从头遍历找到元素
        Entry head = first;
        Entry result = null;
        while(head != null) {
            if(key.equals(head.getKey())) {
                result = head;
                break;
            }
            head = head.getNext();
        }
        return result;
    }
    public void put(Object key, Object value){
        Entry entry = new Entry(key, value);
        Entry head = first.getNext();
        while (head != null) {
            head = head.getNext();
        }
        if(first.getNext() == null) {
            first.setNext(entry);
            last = entry;
            last.setPre(first);
            size++;
            return;
        }
        //头插法加入新元素
        entry.setNext(first.getNext());
        entry.setPre(first);
        first.getNext().setPre(entry);
        first.setNext(entry);
        size++;
        //当size达到最大,删除last元素
        if(size > max) {
            last = last.getPre();
            last.setNext(null);
            size--;
        }
    }
    public Object get(Object key) {
        Entry search = search(key);
        if(search == null) {
            return null;
        }
        //找到后将元素置于头部
        Entry pre = search.getPre();
        Entry next = search.getNext();
        pre.setNext(next);
        if(next != null) {
            next.setPre(pre);
        }
        search.setNext(first.getNext());
        if(first.getNext() != null) {
            first.getNext().setPre(search);
        }
        first.setNext(search);
        return search.getValue();
    }
}
class Entry {
    private Object key;
    private Object value;
    private Entry pre;
    private Entry next;
    public Entry(Object key, Object value) {
        this.key = key;
        this.value = value;
    }
    public Entry getPre() {
        return pre;
    }
    public void setPre(Entry pre) {
        this.pre = pre;
    }
    public Entry getNext() {
        return next;
    }
    public void setNext(Entry next) {
        this.next = next;
    }
    public Object getKey() {
        return key;
    }
    public void setKey(Object key) {
        this.key = key;
    }
    public Object getValue() {
        return value;
    }
    public void setValue(Object value) {
        this.value = value;
    }
}