使用数组与有序集合LinkedHashMap(双向链表)实现一个简单的LRU算法(最近最少使用策略 LRU(Least Recently Used))

什么是LRU算法?

redis大家都玩过吧,你们好奇redis内存数据存满之后会发生什么吗?抛出异常?禁止使用?还是删除数据?其实redis设计了一种内润淘汰机制。

noeviction(默认策略):屏蔽写操作,返回错误(特殊的写操作除外),但是支持删除操作

volatile-lru:使用LRU算法对设置了过期时间的key进行删除。

allkeys-lru:使用LRU算法对所有key进行删除。

allkeys-random:在所有的key中随即淘汰一部分数据。

volatile-ttl:根据过期时间删除key,越快过期,就会被优先执行删除操作。

volatile-random:在设置了过期时间的key中随机淘汰一部分数据。

使用命令查看redis的淘汰机制:

config get maxmemory-policy

看到没有,其中就有一种LRU算法,那LRU到底是什么呢?最近最少使用的就被淘汰(删除),这样说比较抽象,我举个现实中的例子:假如你买了一个衣柜,用来存放衣服,又因为你平时比较喜欢剁手,买着买着发现衣服太多了,衣柜放不下了,房间有没有其他空间存放,这个时候是不是就需要将衣柜里面的某些衣服送给朋友或者丢掉呢?那你处理哪些衣服呢?你是不是会处理掉不怎么穿,并且买了很久的衣服,不会将你昨天买的就处理掉吧,LRU也是这样,他会保留最近被使用的,删除之前最少被使用的数据。

数组实现一个简单的LRU算法

实现思路:
1.创建一个指定长度的数组。
2.判断数组是否已被完全使用,如果没有直接将数据添加数组末尾。
3.如果数组已经被完全使用,判断此数据在数组中书否存在,如存在:将此数据移到数组末尾,其他数据往前移一位;如不存在,删除数组第一位,然后将数组后面的数据往前移一位,最后将数据添加到数组的末尾。

请看代码:

  /**
     * 判断数据是否存在数组中
     * @param arr
     * @param length
     * @param str
     * @return
     */
    public static Integer getIndex(String[] arr, int length, String str) {
        for (int i = 0; i < length; i++) {
            if (str.equals(arr[i])) {
                return i;
            }
        }
        return null;
    }

    /**
     * 使用数组实现LRU算法
     *
     * @param args
     */
    public static void main(String[] args) {
        String[] arr = new String[5];
        String[] newArr;
        int length = arr.length;
        Scanner input = new Scanner(System.in);
        while (true) {
            System.out.println("");
            System.out.println("请输入数据:");
            String str = input.next();
            if ("n".equals(str)) {
                System.exit(0);
            }
            newArr = arr.clone();
            if(null == arr[length - 1]){
                loop:
                for (int i = 0; i < length; i++) {
                    if (null == arr[i]) {
                        arr[i] = str;
                        break loop;
                    }
                }
            }else{
                Integer index = getIndex(arr, length, str);
                if (null == index) {
                    // System.out.println("没有在数组中找到数据");
                    //数组中找不到数据
                    //所有数据左移一位
                    for (int i = 1; i < length; i++) {
                        arr[i - 1] = newArr[i];
                    }
                    arr[length - 1] = str;
                } else {
                    //System.out.println("在数组中找到了数据,下标在:"+index);
                    int newArrLength = newArr.length;
                    for (int i = 0; i < newArrLength - 1; i++) {
                        if (index > i) {
                            arr[i] = newArr[i];
                        } else {
                            arr[i] = newArr[i + 1];
                        }
                    }
                    arr[length - 1] = str;
                }
            }
            //打印结果
            for (int i = 0; i < length; i++) {
                if (i == (length - 1)) {
                    System.out.print(arr[i]);
                } else {
                    System.out.print(arr[i] + ",");
                }
            }

        }

    }

请看结果:

这样,用数组实现一个简单的LRU就完成了,当然,你可以使用集合,还会更简单。

使用链表的集合实现LRU算法

思路:
1.判断集合是否完全被使用,如果没有,将数据添加到集合的末尾。
2.如果集合空间已被完全使用,判断数据在几何中是否出现过,若没有:删除集合中的第一个元素,将数据添加到集合末尾;如果存在,删除存在的元素,然后再将数据添加到集合末尾。
代码实现:

package cn.meiot.test;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;

public class LinkedLRU {


    public static void main(String[] args) {

        Map<Object, Object> map = new LinkedHashMap<Object, Object>(5);
        Scanner input = new Scanner(System.in);
        System.out.println("这是用链表集合实现的LRU=================");
        while (true){
            System.out.println("");
            System.out.println("请输入数据:");
            String str = input.next();
            if ("n".equals(str)) {
                System.exit(0);
            }
            if(map.size() < 5){
                map.put(str,str);
            }else if(null == map.get(str)){
                Map.Entry<Object, Object> head = getHead(map);
                map.remove(head.getKey());
                map.put(str,str);
            }else{
                map.remove(str);
                map.put(str,str);
            }
            System.out.println(map);
        }

    }

    /**
     * 获取第一个元素
     * @param map
     * @param <K>
     * @param <V>
     * @return
     */
    public static <K, V> Map.Entry<K, V> getHead(Map<K, V> map) {
        return  map.entrySet().iterator().next();
    }


}

结果如下:

发布了41 篇原创文章 · 获赞 79 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_33220089/article/details/103522826