zoukankan      html  css  js  c++  java
  • 操作系统-2-存储管理之LRU页面置换算法(LeetCode146)

    LRU缓存机制

    题目:运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。

       它应该支持以下操作: 获取数据 get 和 写入数据 put 。

       获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。

          写入数据 put(key, value) - 如果密钥已经存在,则变更其数据值;如果密钥不存在,则插入该组「密钥/数据值」。

       当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

    示例:  
       LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );

       cache.put(1, 1);
       cache.put(2, 2);
       cache.get(1);       // 返回  1
       cache.put(3, 3);    // 该操作会使得密钥 2 作废
       cache.get(2);       // 返回 -1 (未找到)
       cache.put(4, 4);    // 该操作会使得密钥 1 作废
       cache.get(1);       // 返回 -1 (未找到)
       cache.get(3);       // 返回  3
       cache.get(4);       // 返回  4

    代码:

     1 class LRUCache {
     2 
     3     public LRUCache(int capacity) {
     4 
     5     }
     6     
     7     public int get(int key) {
     8 
     9     }
    10     
    11     public void put(int key, int value) {
    12 
    13     }
    14 }
    15 
    16 /**
    17  * Your LRUCache object will be instantiated and called as such:
    18  * LRUCache obj = new LRUCache(capacity);
    19  * int param_1 = obj.get(key);
    20  * obj.put(key,value);
    21  */

    LRU页面置换算法(最近最少使用算法)(我的另一篇博文讲到了LFU最不经常使用页面置换算法,可以进行比较)

      原理:

        选择最后一次访问时间距离当前时间最长的一页并淘汰之。即淘汰没有使用的时间最长的页
        每页设置访问时间戳,每当页面被访问时,该页面的时间戳被更新;
        发生缺页中断时,淘汰时间戳最小的页面;

        如图:图中的页面为三页,依次向存储中加入432143543215这些数字。

           而存储空间只能存储三个页面,所以会按照上述规则不断淘汰已经存储在页面中的数字。

        

    解题思路(logN的思路):

        知道了LRU的置换规则后,由于此题需要存储的是key和value,所以

          首先,需要建一个类node,存放三样东西,key,value,times(时间戳)

          其次,选择一种合适的数据结构来解决存储优先级问题,此处我们采用内部是小顶堆的PriorityQueue优先级队列用来实现times最小的元素在队头

             但是我们会在让新元素入队之前可能会删除队列中指定元素,当然可以去遍历队列,但是这样太慢了

             我们可以再用一种HashMap的数据集合用来存储节点,以便快速通过node的key来得到整个node。

          最后,便是处理逻辑关系,写题目要求的get,put方法了

    解题代码详解(logN):

     1 public class node implements Comparable<node>{
     2     private int Key;//
     3     private int Value;//
     4     private int Times;//时间戳
     5     node() {}
     6     node(int key, int value, int time) {
     7         this.Key = key;
     8         this.Value = value;
     9         this.Times = time;
    10     }
    11     public int getKey() {
    12         return Key;
    13     }
    14 
    15     public void setKey(int Key) {
    16         this.Key = Key;
    17     }
    18 
    19     public int getValue() {
    20         return Value;
    21     }
    22 
    23     public void setValue(int Value) {
    24         this.Value = Value;
    25     }
    26 
    27     public int getTimes() {
    28         return Times;
    29     }
    30 
    31     public void setTimes(int Times) {
    32         this.Times = Times;
    33     }
    34 
    35     @Override
    36     public int compareTo(node o) {
    37         //实现times最小的元素在队头
    38         return Times - o.Times;
    39     }
    40 }
    41 
    42 class LRUCache {
    43     PriorityQueue<node> KeyValueTimes = new PriorityQueue();//用于实现优先级顺序
    44     Map<Integer, node> nodeset;//用于O(1)取出某个具体的node
    45     public int Capacity = 0;//我的cache中最大容量
    46     public int nownum = 0;//cache的实时元素个数
    47     public int tim = 0;//时间戳
    48 
    49     public LRUCache(int capacity) {
    50         this.Capacity = capacity;//设置cache容量
    51         nodeset = new HashMap<Integer, node>(capacity);//用于O(1)取出某个具体的node,容量依然设置为capacity
    52     }
    53     
    54     public int get(int key) {
    55         if(this.Capacity == 0)//判断容量是否为空,为空则直接返回-1
    56             return -1;
    57         node nownode = nodeset.get(key);//通过HashMap,快速通过key键快速得到node
    58         if (nownode == null) {//如果key这个键没在队列中,则返回-1
    59             return -1;
    60         }else{
    61             KeyValueTimes.remove(nownode);//移除队列中当前的这个node
    62             nownode.setTimes(tim++);//更新当前这个node的时间戳
    63             KeyValueTimes.offer(nownode);//再把它放回去
    64         }
    65         return nownode.getValue();
    66     }
    67     
    68     public void put(int key, int value) {
    69         if(this.Capacity == 0)//判断容量是否为空,为空则不进行put
    70             return;
    71         node thisnode = new node(key,value,tim++);
    72         node oldnode = nodeset.get(key);
    73         if(oldnode == null){//队列里不存在这个key
    74             if(nownum < this.Capacity){//没装满
    75                 KeyValueTimes.offer(thisnode);//在队列里添加新node
    76                 nodeset.put(key,thisnode);//在HashMap里添加新node
    77                 nownum++;//更新当前cache的元素个数
    78             }
    79             else{//装满了,需要LRU,最近最久为使用被移除
    80                 nodeset.remove(KeyValueTimes.poll().getKey());//移除队列里的队头,移除HashMap对应的那个node
    81                 KeyValueTimes.offer(thisnode);//在队列里添加新node
    82                 nodeset.put(key,thisnode);//在HashMap里添加新node
    83             }
    84         }
    85         else{//队列里存在这个key
    86             KeyValueTimes.remove(oldnode);//移除队列里键为key的node,移除HashMap对应的那个node
    87             nodeset.remove(oldnode.getKey());
    88             KeyValueTimes.offer(thisnode);//在队列里添加新node,这里新的node的value值可能会不一样,所以更新了value
    89             nodeset.put(key,thisnode);//在队列里添加新node,这里新的node的value值可能会不一样,所以更新了value
    90         }
    91     }
    92 }
  • 相关阅读:
    同一个IIS绑定多个Htts 站点问题
    开发小程序心得
    在阿里云里申请免费Https证书SSL
    request:fail 小程序要求的 TLS 版本必须大于等于 1.2
    js封装Cookie操作
    数据库日志文件(databasename_log.ldf)太大 如何清除
    sql with(lock) 与事务
    java.lang.VerifyError: com/google/android/gms/measurement/internal/zzw
    Eclipse 导入 Android studio Exception Ljava/lang/UnsatisfiedLinkEror
    Eclipse工程 导入 Android Studio
  • 原文地址:https://www.cnblogs.com/qinqin-me/p/12699642.html
Copyright © 2011-2022 走看看