链表实现LRU缓存淘汰算法

LRU最近最少未使用算法。在OS虚拟存储器那部分。用到了该算法,根据程序的局部性原理,前人设计出了虚拟存储器,每个进程只被分配几个内存块,当进程的内存块被占完了之后。从硬盘上又重新读取了一个内存块的数据量,此时,哪个内存块的内容被换出去比较合适呢?如果置换算法采取的不好,就会导致缺页率上升。进程频繁的发生缺页中断。OS就会频繁的在内存和外存之间替换页面。影响了进程的执行效率,这种现象又称之为"抖动",LRU置换算法的缺页率相对比较低。

缓存是一种提高数据读取性能的技术,在硬件设计、软件开发中都有着非常广泛的应用,比如常见的 CPU 缓存、数据库缓存、浏览器缓存等等。 硬件中的缓存: CPU缓存,而cpu缓存又可以分为寄存器,一级缓存,二级缓存,三级缓存。 软件中的缓存: 数据库缓存,数据库本身产品就自带缓存。redis也可以作为数据库缓存.  浏览器缓存,就是我们常说的Cookie,本质上就是一个文件。

链表删除、增加操作的时间复杂度

单纯的删除操作,时间复杂度为o(1),但是找到要删除的这个数,要需要一点的时间。常见的删除有两种,一种是删除指定值,一种是删除指定位置。

删除给定指针指向的结点: 这种情况是已经找到了要删除的元素,我们只需要执行删除操作即可. 针对单链表而言: 单链表如果要删除一个结点q.必须要知道这个结点的前驱结点是谁,修改前驱结点的指针指向即可.单链表找某个结点的前驱结点,只能从头开始遍历. 临界值 p->next == q;说明p就是q的前驱结点.所以在单链表中,找这个前驱结点的平均时间复杂度为O(n),然后执行删除操作的时间复杂度为O(1). 根据时间复杂度分析的加法法则: 删除给定指针指向的结点 --> 单链表的总的时间复杂度为O(n).

针对双链表而言: 双链表要删除一个结点q.也必须得知道这个结点的前驱结点和后继结点. 修改前驱结点的后继指针next和后继结点的前驱指针prev即可.而针对双链表而言,找q的前驱结点和q的后继结点的时间复杂度都为O(1).而执行删除操作(修改指针指向)的时间复杂度也为O(1). 根据时间复杂度分析的加法法则: 删除给定指针指向的结点 --> 双链表的总的时间复杂度为O(1).

LRU算法

LRU的算法思路是真的简单,概括下: 使用定长链表来保存所有缓存的值,并且最老的值放在链表最后面 当访问的值在链表中时: 将找到链表中值将其删除,并重新在链表头添加该值(保证链表中 数值的顺序是从新到旧) 当访问的值不在链表中时: 当链表已满:删除链表最后一个值,将要添加的值放在链表头 当链表未满:直接在链表头添加。

typedef int DataType;

//定义
class SNode
{
public:
    DataType data;
    SNode* next;
};

class SList
{
public:
    SList();
    SList(int MaxSize);
    ~SList();
    void intsertElemAtBegin(DataType x);      //头部插入节点
    bool findElem(DataType x);              //查找x,存在则返回1,不存在则返回0
    void deleteElemAtEnd();             //删除尾节点
    bool deleteElem(DataType x);    //删除指定节点,如果存在则删除,返回1,如果不存在,则删除失败返回0
    bool isEmpty();                  // 查看链表是否为空,1表示不为空,0表示为空
    bool isFull();                   // 查看链表是否满,1表示不满,0表示满
    void printAll();

    void* findElemOptim(DataType x);     //针对此应用的优化,查找,返回指定元素的前一个节点的指针
    void deleteElemOptim(void* snode);     //针对此应用的优化,删除
private:
    int MaxSize;       // 链表可以存放最大的数据
    int length;             // 链表的长度
    SNode* head;          // 指向头节点

};


/**
 * 1)单链表的插入,删除,查找操作;
 * 2)链表中存储的是 int 类型
 *
 * Author:caozx
 */
#include<iostream>
using namespace std;

// 初始化单链表
SList::SList() {
    head = new SNode;     //申请头节点
    head->next = NULL;
    this->MaxSize = 10;
    this->length = 0;
}
SList::SList(int MaxSize) {
    head = new SNode;     //申请头节点
    head->next = NULL;
    this->MaxSize = MaxSize;
    this->length = 0;
}

// 销毁单链表,要把开辟的空间都释放,然后再销毁。
SList::~SList() {
    SNode* ptr, * temp;
    ptr = head;
    while (ptr->next != NULL) {
        temp = ptr->next;
        ptr->next = ptr->next->next;
        delete temp;
    }
    delete head; //删除头节点
    this->head = NULL;
    this->length = 0;
}

//链表头部插入节点
void SList::intsertElemAtBegin(DataType x) {
    SNode* ptr = new SNode;
    ptr->data = x;

    ptr->next = head->next;
    head->next = ptr;

    this->length++;
}

//查找x,存在则返回1,不存在则返回0

bool SList::findElem(DataType x)
{
    SNode* ptr;
    ptr = head;
    while (ptr->next != NULL) {
        if (ptr->next->data == x) {
            return 1;
        }
        ptr = ptr->next;
    }
    return 0;
}

// 删除尾结点
void SList::deleteElemAtEnd() {
    SNode* ptr, * temp;
    ptr = head;
    while (ptr->next != NULL && ptr->next->next != NULL) {   //倒数第二个节点
        ptr = ptr->next;
    }
    temp = ptr->next;
    ptr->next = temp->next;
    this->length--;
    delete temp;
}

//删除指定节点,
//如果存在则删除,返回1,表示存在且删除成功;
//如果不存在则不删除,返回0,表示不存在该元素,不需要删除,也即删除失败
bool SList::deleteElem(DataType x)
{
    SNode* ptr, * temp;
    ptr = head;
    while (ptr->next != NULL) {
        if (ptr->next->data == x) {
            temp = ptr->next;
            ptr->next = temp->next;
            delete temp;
            this->length--;
            return 1;
        }
        ptr = ptr->next;
    }
    return 0;
}

// 查看链表是否为空,1表示不为空,0表示为空
bool SList::isEmpty()
{
    if (this->length == 0) {  //空
        return 0;
    }
    else {
        return 1;
    }
}

// 查看链表是否满,1表示不满,0表示满
bool SList::isFull()
{
    if (this->length == this->MaxSize) {  //满
        return 0;
    }
    else {
        return 1;
    }
}

// 打印
void SList::printAll()
{
    SNode* ptr;
    ptr = head;
    while (ptr->next != NULL) {
        ptr = ptr->next;
        cout << ptr->data << "   ";
    }
    cout << endl;
}

//针对此应用的优化,查找,
//若存在则返回指定元素的前一个节点的指针
//若不存在,则返回NULL

void* SList::findElemOptim(DataType x)
{
    SNode* ptr;
    ptr = head;
    while (ptr->next != NULL) {
        if (ptr->next->data == x) {
            return (void*)ptr;
        }
        ptr = ptr->next;
    }
    return NULL;
}

//针对此应用的优化,删除

void SList::deleteElemOptim(void* snode)
{
    SNode* ptr, * temp;
    ptr = (SNode*)snode;
    temp = ptr->next;
    ptr->next = temp->next;
    this->length--;
    delete temp;
}
int main(int argc, char const* argv[])
{
    cout << "test " << endl;
    SList slist(10);     //缓存最大10个。
    int num = 0;
    while (1)
    {
        cout << "please enter a number,99999== exit" << endl;
        cin >> num;
        if (num == 99999)
            break;
        /* 未优化
        if(slist.findElem(num)){    //存在
            slist.deleteElem(num);     //把原来的位置删除
            slist.intsertElemAtBegin(num); //在链表头插入
        }
        */
        //优化
        SNode* prePtr = (SNode*)slist.findElemOptim(num);
        if (prePtr != NULL) {    //存在
            slist.deleteElemOptim(prePtr);     //把原来的位置删除
            slist.intsertElemAtBegin(num); //在链表头插入
        }
        else {      //不存在
            if (slist.isFull()) {    //不满
                slist.intsertElemAtBegin(num);
            }
            else {                   //满
                slist.deleteElemAtEnd();
                slist.intsertElemAtBegin(num);
            }
        }
        slist.printAll();
    }
    return 0;
    system("pause");
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值