实现LRU算法的方式有两种:数组和单链表。讲讲我为什么要用链表模拟实现。
其实我们知道,cpu从外存取数据到内存是以块为基本单位的,也就是说cpu取一块连续的地址到内存内,这样说的话是不是对数组友好点?因为数组用连续的地址存储着相同类型的数据。但是在我考虑在实际应用中,如果需要分配的地址过大时,可能会由于各种原理(存储空间有限或者空间碎片化)无法分配一块连续的地址给数组,而且在频繁的插入删除操作面前,数组的时间复杂度太高。所以我觉得链表在LRU实现上虽不能一次性传送块数据,但是实现条件却很简单,没有数组的苛刻,且时间复杂度低。
算法实现:用单链表实现LRU算法
1、将需要放进链表的数据同链表中的数据域比较,是否在链表中
true:如果链表没有达到最大存储上限,将原先存储的那一块内存删除,再将数据头插法插入链表;
false:如果链表没有达到上限,直接插入链表头部,Nowlen+1,空间满删除最后一个节点再将数据插入链表头部
在实现的过程中,当需要删除最后一个节点时,单链表往往需要重新遍历链表找到最后一个节点,比较费时,就将单链表转为双向链表实现,这样插入的时候将tail尾指针给插入的第一个元素,这样删除尾元素之前先将尾指针指向尾元素的pre节点,这样就不用重复遍历节点了。但是后来又想了想,其实时间复杂度还是O(n),然后突然想到我们每次都需要遍历一次指针,那不妨同时遍历到尾,将尾指针赋值给tail,就只需要遍历一次,或许也是个可行的办法。
实现头文件
#pragma once
#pragma once
#include<iostream>
#include<string>
using namespace std;
class linknode
{
public:
char data;
linknode *next;
linknode *pre;
linknode()
{
data = '0';
next = NULL;
pre = NULL;
}
};
class list : public linknode
{
private:
linknode *first;
linknode *tail;
int Maxlen;//链表的最大长度
int Nlen;//链表当前长度
public:
list();//初始化链表
void head_insert(linknode *a);//当有新节点被访问时,将新节点查到链表头部
void omit(linknode *q);//删除当前节点,但节点还是要存储在链表头,所有不用Delete当前节点
bool LRU(char a);//遍历链表查找字符是否在链表中,如何存在则删除
void getlen(int n);//获得链表最大可允许存储的数据大小
void output();//输出链表,测试用
};
list::list()
{
first = new linknode;
tail = new linknode;
Maxlen = 0;
Nlen = 0;
}
void list::head_insert(linknode *a)
{
if (first->next != NULL)//第一个元素插入式时应为first->next没有具体的地址(NULL),需要特殊处理
{
a->next = first->next;
first->next->pre = a;
}
first->next = a;
a->pre = first;
if (Nlen == 0)
tail = first->next;
}
bool list::LRU(char a)
{
linknode *p = first->next;
linknode *pPre = first;
while (p != NULL)//如果链表不为空
{
if (p->data == a)//查找链表中是否存在元素
{
omit(pPre);//存在则删除并重新插入到表头
head_insert(p);
return true;
}
p = p->next;
pPre = pPre->next;
}
if (Nlen == Maxlen)//链表达到上限
{
linknode *t = tail->pre;//重新设置尾指针
tail = t;
tail->next = NULL;//删除尾结点
Nlen--;
}
linknode *Node=new linknode;
Node->data = a;
head_insert(Node);//插入新元素
Nlen++;
return false;
}
void list::getlen(int n)
{
Maxlen = n;
}
void list::omit(linknode *q)
{
q->next = q->next->next;
}
void list::output()
{
linknode *temp = first->next;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
测试cpp
#include"list.h"
int main()
{
char a;
int n;
cout << "请输入内存最大可存入的数:";
cin >> n;
list *List=new list;
List->getlen(n);
while (cin >> a)
{
if (List->LRU(a))
{
List->output();
}
else
{
List->output();
}
}
}