最近最久未使用--LRU算法

1. 什么是LRU?

1.1. 简介

Least Recently Used: 最近最久未使用
算法用途:

页面置换算法
当要访问的页(数据)不在内存中,从内存中选一个页换出去,把要访问的页加入进来。
LRU是一种筛选 置换页 的算法。

1.2. 动机

如果一个页经常被访问,那么大概率之后还会被访问;
而如果一个页很久不被访问,那么大概率之后也不会被访问。

1.3. 算法流程

  当访问一个页时:				// insert
   如果 该页在内存中:			// exist
      移动到队首;			// adjust
   否则:
      如果 内存充足:			// count>=maxCapacity
          插入到队首;
       否则:
          移除队尾元素;		// delete
          插入访问页到队首。

2. 代码实现

利用单向链表维护访问页的顺序

	private class Node{
	    int val;
	    Node next;
	    public Node(){}
	    public Node(int val){
	        this.val = val;
	    }
	}
    Node root = null;		// 根节点
    int count = 0;			// 当前内存中页数

当有访问页来到时:插入函数

    public void insert(int val, int maxCapacity){
        /***
         * 插入访问页 核心
         */
        Node cur = root;
        // step 1 判断是否存在
        if (exist(val)){
            // 存在 移到队首
            adjust(val);
        }else{
            if (count>=maxCapacity){
                /**
                 * 内存满了 要先移除一个页,才能插入。
                 */
                delete();
            }
            count++;
            System.out.println("不存在,插入到队首。");
            // 插入队首
            Node tmp = new Node(val);
            if (cur != null){
                tmp.next = cur;
                root = tmp;
            }else{
                root = tmp;
            }
        }
    }

判断是否存在

	public boolean exist(int val){
	    /**
	     * 判断该页是否在内存中
	     */
	    Node cur = root;
	    while (cur != null){
	        if (cur.val == val)
	            return true;
	        cur = cur.next;
	    }
	    return false;
	}

调整当前页到链表头部

	public void adjust(int val){
	    /**
	     * 元素肯定不为空,至少含有val
	     */
	    System.out.println("已存在,调整位置。");
	    Node cur = root;
	    Node last = null;   // null
	    while (cur.val != val){
	        /**
	         * 肯定是存在的,所以 cur != null 不需要判断
	         * 不存在的话,走另一条路,插入进去。
	         */
	        last = cur;
	        cur = cur.next;
	    }
	    if (last == null){
	        // 第一个元素
	        // 因为本身就在队首了 啥也不需要做,可以不写
	    }else{
	        last.next = cur.next;
	        cur.next = root;
	        root = cur;
	    }
	}

删除链表尾部页

    public int delete(){
        System.out.println("内存满了,移除队尾元素。");
        // 移除队尾的元素
        Node cur = root;
        Node last = null;
        while (cur.next != null){
            last = cur;
            cur = cur.next;
        }
        count--;
        int val = cur.val;
        System.out.println("移除了元素:" + val);
        last.next = null;

        return val;
    }

主函数

    public static void main(String[] args) {
        LRU lru = new LRU();
        int maxCapacity = 5;
        int[] pageId = new int[]{4,7,0,7,1,0,1,2,6};
        for (int i = 0; i < pageId.length; i++) {
            System.out.println("访问页面:" + pageId[i]);
            lru.insert(pageId[i],maxCapacity);
            lru.queryAll();
            System.out.println();
        }
    }

输出:
最近最久未使用--LRU算法_第1张图片

3. 极简版

/***
 * 利用封装好的集合来做,确实很迅速!
 */

import java.util.LinkedList;
public class LRU_LinkedList {
    public static void main(String[] args) {
        int maxCapacity = 5;
        int[] pageId = new int[]{4,7,0,7,1,0,1,2,6};
        LinkedList list = new LinkedList();
        for (int i=0;i<pageId.length;i++){
            int item = pageId[i];
            if (list.contains(item)){
                list.remove(list.indexOf(item));
                list.addFirst(item);
            }else{
                if (list.size()>=maxCapacity){
                    list.removeLast();
                }
                list.addFirst(item);
            }
            for (int i1 = 0; i1 < list.size(); i1++) {
                System.out.print(list.get(i1)+" ");
            }
            System.out.println();
        }
    }
}

输出:
最近最久未使用--LRU算法_第2张图片

你可能感兴趣的:(面试,链表)