A-2 LRU-K(攀拓(PAT)- 程序设计(甲级)2023年春季考试仿真卷)

A-2 LRU-K

分数 25

作者 陈越

单位 浙江大学

Least Recently Used (LRU) cache scheme is to remove the least recently used frame (the one hasn't been used for the longest amount of time) when the cache is full and a new page is referenced which is not there in cache.

LRU-K is a variant of the LRU algorithm, where K represents the number of recent uses. LRU can be considered as LRU-1. Unlike LRU, the LRU-K requires the maintenance of two different queues (for historical access and cache). The data in the historical access queue is not moved to the cache queue until the data is hit K times.

For example, assuming that the length of both queues is 5, and the memory is initialized to be empty. LRU-2 is used to process the data sequence in order: 9,5,6,7,8,3,8,9,5,9,8,3,4,7,5,6. The changes of the historical access queue and the cache queue are shown in the following table:

Data AccessHistorical Aaccess QueueCache Queue
9,5,6,7,89,5,6,7,8Empty
35,6,7,8,3Empty
85,6,7,38
95,6,7,3,98
56,7,3,98,5
96,7,38,5,9
86,7,35,9,8
36,75,9,8,3
46,7,45,9,8,3
76,45,9,8,3,7
56,49,8,3,7,5
648,3,7,5,6

Your job is to implement this LRU-K cache scheme.

Input Specification:

Each input file contains one test case. For each case, the first line gives 3 positive integers: K (≤5), N (≤104) and M (≤105) which are the number of hits for cache, the size of the queues (assuming both queues have the same size) and the number of referenced page ID's. Then M referenced page ID's are given in the next line. A page ID is a number in the range [1,2×104]. All the numbers in a line are separated by a space.

Output Specification:

For each test case, output in the first line the page ID's in the historical access queue, and in the second line, those in the cache queue. The ID's are ordered from front to rear of each queue. All the numbers in a line must be separated by 1 space, and there must be no extra space at the beginning or the end of the line. In case that a queue is empty, output - in a line instead.

Sample Input 1:

2 5 17
9 5 6 7 8 3 8 9 5 9 8 3 4 7 5 6 9

Sample Output 1:

4 9
8 3 7 5 6

Sample Input 2:

3 5 10
9 5 6 7 8 3 8 9 5 9

Sample Output 2:

7 3 8 5 9
-

 
 * 解题思路,因为中间涉及值的查找操作,还有删除操作,但是查询以及删除
 * 操作都可能在序列中间进行,所以不能用优先队列,优先队列只能在队首
 * 进行删除以及查找可以在O(log n)的时间内完成,此时我们就可以想到set
 * 或者map,他们在任何位置进行删除以及查找的时间复杂度都是O(lon n);
 *
 * 由于是LRU算法,所以我们需要两个值来对一个页面进行记录,即页面编号id,
 * 最近页面使用的时间代表,时间代表越大,则表示最近刚使用完;因此可以
 * 定义一个结构体用set来解决;
 *
 * 最先使用的优先对列,可是有几个样例过不去(TLE),现在想想也能想明白;

/**
 * 解题思路,因为中间涉及值的查找操作,还有删除操作,但是查询以及删除
 * 操作都可能在序列中间进行,所以不能用优先队列,优先队列只能在队首
 * 进行删除以及查找可以在O(log n)的时间内完成,此时我们就可以想到set
 * 或者map,他们在任何位置进行删除以及查找的时间复杂度都是O(lon n);
 * 
 * 由于是LRU算法,所以我们需要两个值来对一个页面进行记录,即页面编号id,
 * 最近页面使用的时间代表,时间代表越大,则表示最近刚使用完;因此可以
 * 定义一个结构体用set来解决;
 * 
 * 最先使用的优先对列,可是有几个样例过不去(TLE),现在想想也能想明白;
*/

#include <iostream>
#include <algorithm>
#include <vector>
#include <set>

using namespace std;

struct Infor
{
    int id, flag;
    bool operator < (const Infor& a) const
    {
        //先按照flag从小到大,如果flag相等则按照id从小到大排序
        //请注意,比较关系一定要写完全,不能只写成flag < a.flag;
        //当b.flag == a.flag 时,set就不知道哪个在前,哪个在后,
        //或者干脆不知道 a 是否等于 b,因为 a.flag 确实不等于b.flag啊,
        //你没有显示的告诉id 和 a.id 的关系
        if(flag != a.flag) 
            return flag < a.flag;
        else 
            return id < a.id;
    }
};
const int N = 2e4+10;
set<Infor> cache, hist; 
int idx[N]; //最近使用页面的时间代表
int cnt[N]; //页面在history队列中被使用的次数
int k, n, m;

//输出结果
void Print(set<Infor> st)
{
    if(st.empty())  puts("-");
    else
    {
        bool spa = false;
        for(auto ele : st)
        {
            if(spa) cout << ' ';
            else spa = true;
            cout << ele.id;
        }
        cout << endl;
    }
}

int main()
{
    cin >> k >> n >> m;
    
    for(int i=0; i<m; ++i)
    {
        int id;
        cin >> id;
        
        //id页面在cache中
        if(cache.find({id, idx[id]}) != cache.end())
        {
            //将id加在cache的末尾
            cache.erase({id, idx[id]});
            idx[id] = i;
            cache.insert({id, idx[id]}); 
        }
        else
        {
            //id在hist中
            if(hist.find({id, idx[id]}) != hist.end())
            {
                ++cnt[id];
                
                //id或者加在hist末尾,或者加在cache末尾(当次数达到k)
                hist.erase({id, idx[id]});
                idx[id] = i;
                
                if(cnt[id] == k)
                {
                    //id加在cache末尾(当次数达到k)
                    cache.insert({id, idx[id]});
                    cnt[id] = 0;
                    if(cache.size() > n)
                        cache.erase(cache.begin()); 
                    //超过容量,去掉“队首”的页面
                }
                else
                    //id加在hist末尾
                    hist.insert({id, idx[id]});
            }
            else //id不在hist中,id第一次被调入hist中
            {
                ++cnt[id];
                idx[id] = i;
                hist.insert({id, idx[id]});
               
                } if(hist.size() > n)
                {
                    int id = hist.begin()->id;;
                    hist.erase(hist.begin());
                    cnt[id] = 0;
            }
        }
    }
            
    
    Print(hist);
    Print(cache);
    
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LRU(Least Recently Used)是一种常见的缓存淘汰算法,它的基本思想是:将最不常用的数据最先淘汰掉。 具体实现方式通常是将缓存空间划分为若干个桶(bucket),每个桶中存储一组数据,同时记录它们最后一次被访问的时间。当缓存空间满了,需要淘汰一些数据时,LRU算法会根据数据最近使用的频率和时间进行淘汰。 算法的核心思想是通过计数器(例如最近访问计数器)和哈希表(或排序列表)来实现。计数器用于记录每个数据项最后一次被访问的时间,哈希表或排序列表用于快速查找和删除数据项。 具体实现步骤如下: 1. 当缓存空间满了,需要淘汰一些数据时,遍历缓存中的所有数据项,并记录它们最后一次被访问的时间。 2. 根据时间戳和计数器的值,将数据项按照最近使用的频率进行排序。 3. 将排名最靠后的数据项从缓存中删除,并释放相应的空间。 4. 如果需要继续淘汰数据,重复步骤1-3,直到缓存空间不再满为止。 这种算法的优点是实现简单,易于理解和实现,并且具有较好的性能和效率。但是,它也有一些缺点,例如当缓存命中率较低时,需要频繁地进行淘汰和替换操作,导致缓存命中率进一步下降。此外,如果需要支持高并发访问,还需要考虑并发控制和线程安全等问题。 总之,LRU算法是一种常用的缓存淘汰算法,适用于需要快速响应和低延迟的应用场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值