LRU调度算法

LRU:Least Recently Used
中文名:最近最久未使用调度算法

定义

什么是LRU?
它是按照一个非常著名的计算机操作系统基础理论得来的:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。 基于这个思想,会存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。在计算机中大量使用了这个机制,它的合理性在于优先筛选热点数据,所谓热点数据,就是最近最多使用的数据!因为,利用LRU我们可以解决很多实际开发中的问题,并且很符合业务场景。
简而言之,LRU调度算法每次淘汰的是最近最久未使用的页面,它不会出现像FIFO算法那样并不是每次都是淘汰最老页面,LRU算法淘汰的永远是最近最久未使用的页面,当访问到一个已存在于缓存队列中的页面时,与FIFO调度算法不同的是它会把访问到的页面移到队尾,即重新对队列进行排序。当访问到已存在于缓存中的页面且处在队尾时,保持队列不变。除此之外,都要将队列进行重新排序,将访问到的页面设置为最新页面(即队尾位置)。
定义部分来源

定义过于抽象,下面通过一个实例来更加深刻了解LRU算法

假设缓存大小为3,访问页面顺序为2,6,4,8,5,4,1,4,6,3,9。

可以观察与FIFO调度算法不同之处

->2
->6 2
->4 6 2
->8 4 6
->5 8 4
->4 5 8 4调入内存,但4已经存在,故内存结构发生变化
->1 4 5
->4 1 5 4调入内存,但4已经存在,故内存结构发生变化
->6 4 1
->3 6 4
->9 3 6

C语言代码

#include<stdio.h>
#define MAX 3//缓存最大页面容量 
typedef struct lru{
	int lru[MAX];//存放页面号 
}LRU;

int main()
{
	int temp = -1;//充当中间变量,暂时缓存一个值 
	int flag = 0;//0表示访问的这个页面是一个新页面,1表示访问的这个页面已存在于缓存中 
	int data;//页面号 
	int mid;//充当中间变量,暂时缓存一个值 
	LRU L;
	for(int i = 0; i < MAX; i++)
	{
		L.lru[i] = -1;
	}
	for(int i = 0; i < MAX; i++)
	{
		flag=0;
		printf("请输入第%d个页面号:",i);
		scanf("%d",&data);
		for(int j = 0; j < MAX; j++)
		{
			if(data == L.lru[j])//如果这个页面已存在于缓存中 
			{
				flag = 1;
				temp = j; 
			} 
		}
		if(flag != 1)//如果这个页面不存在于缓存中 
		L.lru[i] = data;
		else//如果这个页面已存在于缓存中 
		{
			printf("你输入的页面已存在,已更新你的访问缓存!\n");
			if( i-temp != 1 )//temp就是j 
			{
				for(int d = 0; d < i-1; d++)
				{
					L.lru[d] = L.lru[d+1];
					if(d+1 == i-1)
					{
						L.lru[d+1] = data;
						break;
					}
				
				}
			}
			printf("\n");
			for(int s = i-1; s >= 0; s--)
			printf("第%d个页面-> %d\n",s,L.lru[s]);
			printf("\n");
			i--;
		}
		
	}
	printf("开始页面分别为\n");
	printf("\n");
	for(int i = MAX-1; i >= 0; i--)
	printf("第%d个页面-> %d\n",i,L.lru[i]);
	printf("\n");
	
	while(true)//已存在3个元素,每输入一个元素都进行一次比较 
	{
		flag = 0;
		printf("请输入一个新的页面:");
		scanf("%d",&data);
		for(int i = 0; i < MAX; i++)
		{
			if(data == L.lru[i])//如果这个页面已存在于缓存中 
			{
				flag = 1;
				mid = i;//缓存已存在于缓存中的页面地址 
			}
		}
		if(flag == 1)//如果这个页面已存在于缓存中 
		{
			if( !(mid+1 == MAX) )
			for(int i = mid; i < MAX-1; i++)//MAX是因为这里输入的数据是data  ?
			{
				L.lru[i] = L.lru[i+1];
				if(i+1 == MAX-1)
				{
					L.lru[i+1] = data;
					break;
				}
			}
		}
		else//如果这个页面不存在于缓存中 
		{
			for(int i = 0; i < MAX-1; i++)//MAX-1是因为数组存储页面号的最后一个是在MAX-1上,而输入的data相当于是在MAX位置上 
			{		   //比如MAX=3,那么它交换数据时是->  0<--1; 1<--2; 2<--MAX 一共两次循环,最后一次循环执行最后两句 
				L.lru[i] = L.lru[i+1];
				if(i+1 == MAX-1)
				{
					L.lru[i+1] = data;
					break; 
				}
			}
		}
		printf("换替换后的页面结果为\n");
		printf("\n");
		for(int i = MAX-1; i >= 0; i--)
		printf("第%d个页面-> %d\n",i,L.lru[i]);
		printf("\n");
	}
	return 0;
}

执行结果

请输入第0个页面号:5
请输入第1个页面号:6
请输入第2个页面号:5
你输入的页面已存在,已更新你的访问缓存!

第1个页面-> 50个页面-> 6

请输入第2个页面号:6
你输入的页面已存在,已更新你的访问缓存!

第1个页面-> 60个页面-> 5

请输入第2个页面号:4
开始页面分别为

第2个页面-> 41个页面-> 60个页面-> 5

请输入一个新的页面:6
换替换后的页面结果为

第2个页面-> 61个页面-> 40个页面-> 5

请输入一个新的页面:5
换替换后的页面结果为

第2个页面-> 51个页面-> 60个页面-> 4

请输入一个新的页面:3
换替换后的页面结果为

第2个页面-> 31个页面-> 50个页面-> 6

请输入一个新的页面:

总的来说,这个算法也比较简单,但它同FIFO算法比较有明显的改进,可以理解为是FIFO的改进版。作者用的是结构体实现。
本人菜鸟一枚妥妥,可能代码写的不规范也可能代码有冗余存在,或者定义出现的名词不规范等问题,欢迎各位大佬指教。

LRU(Least Recently Used)是一种常见的页面置换算法,也可以用于缓存淘汰策略。在LRU算法中,缓存满时,会将最近最少使用的数据淘汰掉,以腾出空间存储新的数据。下面是一个C++实现的LRU缓存类的示例代码: ```c++ #include <iostream> #include <unordered_map> #include <list> using namespace std; class LRUCache { private: int capacity; unordered_map<int, pair<int, list<int>::iterator>> cache; list<int> lru; public: LRUCache(int capacity) { this->capacity = capacity; } int get(int key) { if (cache.find(key) == cache.end()) { return -1; } // 将访问的元素移到链表头部 lru.erase(cache[key].second); lru.push_front(key); cache[key].second = lru.begin(); return cache[key].first; } void put(int key, int value) { if (cache.find(key) != cache.end()) { // 更新元素的值,并将其移到链表头部 lru.erase(cache[key].second); lru.push_front(key); cache[key] = {value, lru.begin()}; } else { if (cache.size() == capacity) { // 淘汰最近最少使用的元素 cache.erase(lru.back()); lru.pop_back(); } // 将新元素插入链表头部 lru.push_front(key); cache[key] = {value, lru.begin()}; } } void print() { for (auto it = lru.begin(); it != lru.end(); ++it) { cout << *it << " "; } cout << endl; } }; ``` 在上面的代码中,LRUCache类包含三个私有成员变量:capacity表示缓存的容量,cache是一个哈希表,用于存储键值对和对应的链表迭代器,lru是一个双向链表,用于存储键的访问顺序。LRUCache类提供了get和put两个公有方法,分别用于获取和插入元素。在get方法中,如果元素存在,则将其移到链表头部,并返回其值;否则返回-1。在put方法中,如果元素已存在,则更新其值,并将其移到链表头部;否则,如果缓存已满,则淘汰最近最少使用的元素,并将新元素插入链表头部。LRUCache类还提供了一个print方法,用于打印当前缓存中的所有键。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

eeeasyFan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值