LRU算法

LRU算法

LRU(Least recently used,最近最少使用)最近使用的数据会在未来一段时期内仍然被使用,已经很久没有使用的数据很有可能在未来较长的一段时间内仍然不会被使用。基于这个思想,会存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。

最常见的实现是使用一个链表保存缓存数据,详细算法实现如下: 
这里写图片描述 

添加:首先判断链表是否超过容量,当链表满的时候,将链表尾部的数据丢弃。 如果是key-value数据,判断数据是否存在,如果存在,不用继续操作,如果是不存在,直接放在链表头后面,其他的元素顺序往下移动;
访问:每当缓存命中(即缓存数据被访问),在头节点的可以不用管,如果是在中间位置或者尾巴,就要将数据移动到头节点后面;
修改:修改操作也一样,修改原值之后,如果头节点后面的可以不用管,如果是在中间位置或者尾巴,就要将数据移动到头节点后面;
删除:直接删除节点,其他元素顺序移动;

实现过程需要注意:

1.添加、删除影响的范围是本身节点及左右两边。

2.访问、修改影响的影响本身节点及左右两边外,还影响头指针和头指针后的节点,访问和修改是需要移动到头指针后面。

#include<stdio.h>
#include<malloc.h>
#define Size 10
int size = 0;


typedef struct doubleLink  doubleLinkNode;
struct doubleLink{
    int value ;
    doubleLinkNode *pre;
    doubleLinkNode *next;
};

//创建双链表的头节点
doubleLinkNode * create(){
    doubleLinkNode *head;
    head = (doubleLinkNode*)malloc(sizeof(doubleLinkNode));
    head->pre = NULL;
    head->next =NULL;
    return head;
}



//新增节点,在双链表头:在头部插入,直接放到头指针后面
int add(doubleLinkNode *head,int value){
    if(head == NULL)return -1; 
    doubleLinkNode *t=head;
    //删除最后一个节点
    if(size>=Size){
        while(t->next!=NULL){
            t = t->next;
         }
        t->pre->next =NULL;
        //删除最后一个节点
        free(t);
        size--;
    }
    doubleLinkNode *node;
    node = (doubleLinkNode*)malloc(sizeof(doubleLinkNode));
    node ->value = value;
    node ->next = head->next;
    node ->pre = head;
    if(head->next!=NULL)
        head->next->pre = node;
    head->next = node;
    size++;
    return 1;
}


//打印链表
int PrintLink(doubleLinkNode *head){
    if(head == NULL)return -1; 
    printf("
");
    doubleLinkNode *t = head;
    while(t->next!= NULL){
        //这里这样做可以不打印第一个节点:头节点,先将t赋值下一个节点
        t= t->next; 
        printf("%d ",t->value);
    }  
    return 1;
}
//通过
//判断链表是否为空
int Isempty(doubleLinkNode *head){
    if(head == NULL)return -1; 
    if(head->next !=NULL)return 1;
    return 0;
}

//计算链表长度
int Length(doubleLinkNode *head){
    if(head == NULL)return -1; 
    doubleLinkNode *t = head;
    int len = 0;
    while(t->next !=NULL){
        len++;
        t = t->next;
    }
    return  len;
}

//从链表删除节点
int deletenode(doubleLinkNode *head,int index){
    if(head == NULL)return -1; 
    //找到这个节点
    doubleLinkNode *t = head;
    int  i = 0;
    while((t->next!=NULL)&&(i<index)){
        t = t->next;
        i++;
    }
    //这个节点存在
    if((i==index)&&(i!=0)){
        //且这个节点为最后一个节点
        if(t->next==NULL){
            t->pre->next =NULL;
        }else{//不为最后一个节点 
           t->pre->next =  t->next;
           t->next->pre =  t->pre;
        }
        //删除节点
        free(t);
        size--;
    }
    return 0;
}

//删除整个链表,释放内存
doubleLinkNode * delete(doubleLinkNode *head){
    if(head == NULL)return NULL; 
    doubleLinkNode *t = head; 
    while(t->next!=NULL){
        t = t->next;
        free(t->pre);
    }
    //删除最后一个节点
    free(t);
    head = NULL;
    size = 0;
    return head;
}

//获取某个节点对象
doubleLinkNode * GetNode(doubleLinkNode *head,int index){
    if(head == NULL)return NULL; 
    doubleLinkNode *t = head;
    int i =0;
    while((t->next!=NULL)&&(i<index)){
        t = t ->next;
        i++;
    }
    if((i==index)&&(i!=0)){
        if((t->next!=NULL)||(i==1)){ //此节点不为最后一个节点
            if(i != 1){
                t->next->pre =  t->pre;
                t->pre->next =  t->next;
                t->next = head->next;
                t->pre = head;
                head->next->pre = t; 
                head->next = t;
            }
        }else{ //此节点为最后一个节点
             t->pre->next =  NULL;
             t->next = head->next;
             t->pre = head;
             head->next->pre = t; 
             head->next = t;
        }
        //上面一段代码有重复的地方,为了逻辑清晰,可以不处理
        return t;  
    }
    return NULL;
}

//中间:打印从自己到最前或者最后一个节点以前的节点
//后面:不能打印自己,从自己前面或者后面的节点打印到最前或者最后一个节点

//从一个节点,向前、向后遍历
int Printpre(doubleLinkNode *node){
    if(node == NULL)return -1; 
    printf("
");
    while(node->pre!=NULL){
        //头指针不存储值,放中间,不打印第一个节点
        printf("%d ",node->value);
        node = node ->pre;
    }
    return 1;
}
//打印自己到最后一个节点
int Printnext(doubleLinkNode *node){
    if(node == NULL)return -1; 
     printf("
");
     printf("%d ",node->value);
    while(node->next!=NULL){
        node = node ->next; 
        printf("%d ",node->value);
    }
    return 1;
}
int main() {
    doubleLinkNode *head = create();
    //添加节点
    add(head,2);
    add(head,3);
    add(head,4);
    add(head,7);
    add(head,8);
    add(head,34);
    add(head,54);
    add(head,22);
    add(head,33);
    add(head,11);
    //打印双链表
    PrintLink(head);
    printf("双链表长度:%d
",Length(head));
    
    //此时这里再插入会超过容量,会删除最后一个节点
    add(head,222);
    PrintLink(head);
    printf("双链表长度:%d
",Length(head));
    
    //删除第三个节点
    deletenode(head,3);
    PrintLink(head);
    printf("双链表长度:%d
",Length(head));
    
    //获取第三个节点,此时第三个节点放到头指针后面
    doubleLinkNode *node = GetNode(head,0);
    PrintLink(head);
    printf("双链表长度:%d
",Length(head));
    //从获取的第三个节点,开始往前,往后遍历,第三个节点被移到头指针后面,此时变为第一个节点
    Printpre(node);
    Printnext(node);
    return 0;
}
原文地址:https://www.cnblogs.com/-wenli/p/12511196.html