LRU算法(Least Recently Used):最近最久未使用法,操作系统中页面置换中的经典算法, 当内存中分配的页面满的时候, 则需要将内存中最久未被使用的页面用新的页面替换出去.
定义页面的数据结构
#define PAGE_COUNT_MAX 20 //页面最大数量
#define DEFAULT_NUM -1 //默认的初值页面号码
typedef struct Page {
int num;//页面号码
int time;//在内存中未访问的时间段
}PINFO;
这里定义了PAGE_COUNT_MAX,表示输入的时候,内存中最多同时存储的页面数量.
DEFAULT_NUM表示初始化的时候,在未输入页面走向的时,默认的页面号码值,为了后面便于判断和操作.
Page:页面数据结构.
num:页面的号码.
time:在内存中的未访问的时间长度(目前这个字段没有起到很大的作用,留作扩展用).
使用数组模拟.
1.定义了内存中存放的数组M.
2.初始化页面的走向数组P.
3.当有新的页面(N)需要调入内存的时候.
3.1.判断此时内存中(M)是否有这个页面(N),如果M中存在此页面(不缺页),则将当前页面和内存中的M[0]位置页面互换位置.
3.2,如果M中不存在此页面(缺页了),则需要判断,此时内存中(M)是否满了.
如果M未满,则顺序添加到数组的末尾.
如果M满了,则将末尾之前的页面顺序往后移动一个位置,将新页面N添加到M[0]位置.
//重置页面走向
void resetInputPagesInfo(void);
//重置内存页面
void resetMemoryPagesInfo(void);
//初始化内存页面容量
void initMemoryPages(void);
//初始化页面走向
void initInputPages(void);
//打印内存中页面最大容量
void printfMemoryPageSize(void);
//打印页面的走向列表
void printfInputPage(void);
//页面操作菜单
int menuPage(void);
//打印分割线
void printfPageLine(int num,char c,int nextLine);
//打印内存中的集合. length:当前内存的长度
void printfMemoryPages(PINFO pageInfos[],int length);
//内存中的队列是否满
//返回值:下一个空的位置角标. -1:表示已经满了
int isMemoryFull(void);
//将新的页面添加到内存未满的集合中(不包含)
void addPageToNoFullByNoContain(PINFO pInfo,int nextEmptyPosition);
//将新的页面添加到内存集合满的状态(不包含)
void addPageToFullByNoContain(PINFO pInfo);
//将新的页面添加到内存中包含此页面集合中,containPosition为角标
void addPageByContain(PINFO pInfo,int containPosition);
//开始调度
void startDispatch(void);
1.定义内存页面数组.
2.定义页面走向数组.
3.定义内存中待输入页面数量(大于0小于等于PAGE_COUNT_MAX数值).
4.定义待输入的页面走向的数组大小.
#include "LruAlgorithm.h"
PINFO pagesMemory[PAGE_COUNT_MAX];//在内存中存储的页面数量(按照最近一次在内存中访问的时间:从小到大排列,最后访问的在第一个位置,依次类推
PINFO pagesInpuntPage[PAGE_COUNT_MAX*2];//可以输入的页面的数量
int memory_size;//内存中页面的数量
int input_size;//页面走向的数量
//判断队列中是否包含此页面
//返回值:当前页面在内存中的位置角标,-1表示不包含
int isContainPage(PINFO array[],int length,PINFO value){
for(int i=0;i<length;i++){
if(array[i].num==value.num){
return i;
}
}
return -1;
}
//重置内存页面
void resetMemoryPagesInfo(){
memory_size=0;
for(int i=0;i<PAGE_COUNT_MAX;i++){
pagesMemory[i].num=DEFAULT_NUM;
pagesMemory[i].time=DEFAULT_NUM;
}
resetInputPagesInfo();
}
//重置页面走向
void resetInputPagesInfo(){
input_size=0;
for(int i=0;i<PAGE_COUNT_MAX*2;i++){
pagesInpuntPage[i].num=DEFAULT_NUM;
pagesInpuntPage[i].time=DEFAULT_NUM;
}
}
//初始化内存页面
void initMemoryPages(){
resetMemoryPagesInfo();
printf("请输入内存中页面容量数量(大于0):");
scanf("%d",&memory_size);
//如果超过了最大值,则设置为最大值
if(memory_size>PAGE_COUNT_MAX){
memory_size=PAGE_COUNT_MAX;
}
if(memory_size<=0){
printf("内存容量页面应该大于0");
}
}
//初始化页面走向
void initInputPages(void){
resetInputPagesInfo();
printf("请输入页面调度的走向(输入-1结束):\n");
int position=0;
do{
int num;
scanf("%d",&num);
if(num==-1){
break;
}
pagesInpuntPage[position].num=num;
position++;
input_size=position;
}while(position<PAGE_COUNT_MAX*2);
//如果页面走向为0,那么直接退出
if(input_size<=0){
printf("页面数量应该大于0\n");
}else{
printfInputPage();
}
}
//打印内存中页面最大容量
void printfMemoryPageSize(void){
if(memory_size<=0){
printf("还未初始化内存页面容量(菜单编号1)\n");
}else{
printf("内存中可以存储的最大页面数:%d\n",memory_size);
}
}
//打印页面的走向列表
void printfInputPage(void){
if(input_size<=0){
printf("页面走向序列:还未初始化页面走向(菜单编号2)\n");
}else{
printf("页面走向序列(%d):",input_size);
printf("[");
for(int i=0;i<input_size;i++){
if(i==0){
printf("%d",pagesInpuntPage[i].num);
}else{
printf(",%d",pagesInpuntPage[i].num);
}
}
printf("]\n");
}
}
//打印分割线
void printfPageLine(int num,char c,int nextLine){
for(int i=0;i<num;i++){
printf("%c",c);
}
if(nextLine==1){
printf("\n");
}
}
//打印内存中的集合.
void printfMemoryPages(PINFO pageInfos[],int length){
printf("按照在内存中未访问的时间从短到长排列(%d):",length);
printf("[");
for(int i=0;i<length;i++){
if(i==0){
printf("%d",pageInfos[i].num);
}else{
printf(",%d",pageInfos[i].num);
}
}
printf("]\n");
}
//内存中的队列是否满
//返回值:下一个空的位置角标. -1:表示已经满了
int isMemoryFull(){
for(int i=0;i<PAGE_COUNT_MAX;i++){
if(pagesMemory[i].num==-1){
//找到了空的位置
if(i==memory_size){
return -1;
}else{
return i;
}
}else if(i==PAGE_COUNT_MAX-1 &&pagesMemory[i].num!=-1){
return -1;
}
}
return -1;
}
//将新的页面添加到内存未满的集合中(不包含)
void addPageToNoFullByNoContain(PINFO pInfo,int nextEmptyPosition){
printf("缺页了->新页码:%d,移除的页码:%s\n",pInfo.num,"无");
//1.首先逆向遍历移动集合中元素:位置+1,并且time+1.
for(int i=nextEmptyPosition-1;i>=0;i--){
pagesMemory[i+1].num=pagesMemory[i].num;
pagesMemory[i+1].time=pagesMemory[i].time+1;
}
//2.将新的页面添加到0的位置,并且时间设置为0
pagesMemory[0].num=pInfo.num;
pagesMemory[0].time=0;
}
//将新的页面添加到内存集合满的状态(不包含)
void addPageToFullByNoContain(PINFO pInfo){
printf("缺页了->新页码:%d,移除的页码:%d\n",pInfo.num,pagesMemory[memory_size-1].num);
//1.首先逆向移动集合中元素:位置+1,并且time+1.
for(int i=memory_size-1-1;i>=0;i--){
pagesMemory[i+1].num=pagesMemory[i].num;
pagesMemory[i+1].time=pagesMemory[i].time+1;
}
//2.将新的页面添加到0的位置,并且时间设置为0
pagesMemory[0].num=pInfo.num;
pagesMemory[0].time=0;
}
//将新的页面添加到内存中包含此页面集合中,containPosition为角标
void addPageByContain(PINFO pInfo,int containPosition){
printf("不缺页->新页码:%d\n",pInfo.num);
//1.先查找当前结点在集合中的位置角标i
int position=containPosition;
//2.将i结点之后的结点time+1
for(int i=position+1;i<memory_size;i++){
if(pagesMemory[i].time!=-1){
pagesMemory[i].time=pagesMemory[i].time+1;
}
}
//3.将i结点之前的结点往后移动位置+1,并且时间time+1
for(int i=position-1;i>=0;i--){
pagesMemory[i+1].num= pagesMemory[i].num;
pagesMemory[i+1].time= pagesMemory[i].time+1;
}
//4.将i结点添加到第0的位置,时间设置为0
pagesMemory[0].num=pInfo.num;
pagesMemory[0].time=0;
}
//开始调度
void startDispatch(){
printf("<<开始调度>>\n");
int lackPageCount=0;
//页面调度顺序
for(int i=0;i<input_size;i++){
int containPosition=isContainPage(pagesMemory, memory_size, pagesInpuntPage[i]);
if(containPosition!=-1){
//内存中存在此页面--不缺页
addPageByContain(pagesInpuntPage[i],containPosition);
printfMemoryPages(pagesMemory,memory_size);
}else{
lackPageCount++;
//内存中不存在此页面--缺页
int position=isMemoryFull();
if(position!=-1){
//表示内存集合未满
addPageToNoFullByNoContain(pagesInpuntPage[i],position);
printfMemoryPages(pagesMemory,position+1);
}else{
//内存中集合满了
addPageToFullByNoContain(pagesInpuntPage[i]);
printfMemoryPages(pagesMemory,memory_size);
}
}
}
printf("调度结果:页面总数:%d,缺页次数:%d,缺页率:%.2f%s\n",input_size,lackPageCount,(float)lackPageCount/input_size*100,"%");
printf("<<调度结束>>\n");
}
调用的顺序:
1.首先必须先初始化内存页面容量.
2.再初始化内存页面走向.
3.然后才可以页面调度.
如果操作后面的步骤,则前面的步骤必须完成.
//页面操作菜单
int menuPage(void){
int result=1;
printfPageLine(50,'*',1);
printf("%*s%s\n",18,"","<<页面管理(LRU算法)>>");
printf("%*s%s\n",20,"","1.初始化内存页面容量");
printf("%*s%s\n",20,"","2.查看内存页面大小");
printf("%*s%s\n",20,"","3.初始化页面走向");
printf("%*s%s\n",20,"","4.查看页面走向");
printf("%*s%s\n",20,"","5.开始调度页面");
printf("%*s%s\n",20,"","6.退出系统");
printf("%*s%s",18,"","请输入菜单编号(1-6):");
int menuNum;
do{
scanf("%d",&menuNum);
if(menuNum<1 || menuNum>6){
printf("%*s%s",18,"","输入错误,请重新输入:");
}
}while(menuNum<1 || menuNum>6);
printfPageLine(50,'*',1);
switch (menuNum) {
case 1:
initMemoryPages();
menuPage();
break;
case 2:
printfMemoryPageSize();
menuPage();
break;
case 3:
initInputPages();
menuPage();
break;
case 4:
printfInputPage();
menuPage();
break;
case 5:
if(memory_size<=0){
printf("请先初始化内存容量(菜单编号1)\n");
}else if(input_size<=0){
printf("请先初始化页面走向(菜单编号2)\n");
}else{
startDispatch();
}
menuPage();
break;
case 6:
printf("退出成功,欢迎下次使用\n");
// exit(0);
result=0;
break;
}
return result;
}
1.此代码是在mac系统上的开发工具xcode上开发的,如果下载的代码要在WIndow系统上的VC6.0或者DevC++开发工具上运行,可能会存在中文乱码问题.
解决办法:
1.1可以在window上使用记事本打开,另存为:选择window系统上开发工具支持的编码方式.
1.2可以使用笨方法:在window开发工具上新建文件,然后使用记事本打开源代码后复制到新建的文件上.
2.如果出现不能运行的问题,就是方法中局部变量问题.
例如:
//判断队列中是否包含此页面
//返回值:当前页面在内存中的位置角标,-1表示不包含
int isContainPage(PINFO array[],int length,PINFO value){
for(int i=0;i<length;i++){
if(array[i].num==value.num){
return i;
}
}
return -1;
}
就需要把i抽取到方法体的顶部.
//判断队列中是否包含此页面
//返回值:当前页面在内存中的位置角标,-1表示不包含
int isContainPage(PINFO array[],int length,PINFO value){
int i;
for(i=0;i<length;i++){
if(array[i].num==value.num){
return i;
}
}
return -1;
}
自己亲测在window上使用上述两种办法,解决了问题.mac编译工具到window编译工具可以运行.