LRU算法

LRU算法

LRU

Least Recently Used 最近最久未使用
LRU的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。

实现LRU

  1. 用数组来存储数据,给每一个数据项标记一个访问时间戳,每次插入新数据项的时候,先把数组中存在的数据项的时间戳自增,并将新数据项的时间戳置为0并插入到数组中。每次访问数组中的数据项的时候,讲被访问的数据项的时间戳置为0。当数组空间已满时,将时间戳最大的数据项淘汰。简单实现:
//
//  main.c
//  lru
//
//  Created by 李龙 on 2018/12/10.
//  Copyright © 2018 李龙. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10
#define ERROR 0
#define SUCCESS 1

//结点数据
typedef struct {
    int data;   //数据
    int num;    //时间戳
} Node;

//缓存数据
typedef struct {
    struct Node *caches[MAXSIZE];   //缓存数组
    int length;                     //当前长度
} *Cache, Caches;


//判断是否有缓存
int hasCache(Cache cache, int data) {
    
    if (cache->length == 0) {
        return ERROR;
    }
    
    for (int i = 0; i < cache->length; i++) {
        Node *node = (Node *)cache->caches[i];
        if (node->data == data) {
            //时间戳置为0
            node->num = 0;
            return SUCCESS;
        }
    }
    
    return ERROR;
}

//添加缓存
void addCache(Cache cache, int data) {
    
    int i;
    //所有时间戳+1
    for (i = 0 ; i < cache->length; i++) {
        Node *node = (Node *)cache->caches[i];
        node->num++;
    }
    
    //有缓存则将该数据时间戳置为0, 已在hasCache中置为0了
    if (hasCache(cache, data) == SUCCESS) {
        
        //没有缓存
    } else {
        //缓存数没有最大,则进行创建结点加入数组, 时间戳为0
        if (cache->length < MAXSIZE) {
            Node *node = (Node *)malloc(sizeof(Node));
            node->data = data;
            node->num = 0;
            //数组长度+1
            cache->caches[cache->length] = (struct Node *)node;
            cache->length++;
            
            //若为最大值, 则找到时间戳最大的, 数据替换, 时间戳置为0
        } else {
            int j = 0, max = 0;
            for (i = 0; i < cache->length; i++) {
                Node *node = (Node *)cache->caches[i];
                if (node->num > max) {
                    j = i;
                    max = node->num;
                }
            }
            Node *node = (Node *)cache->caches[j];
            node->data = data;
            node->num = 0;
        }
    }
}

int main(int argc, const char * argv[]) {
    
    Cache cache = (Cache)malloc(sizeof(Caches));
    cache->length = 0;
    
    int i, data;
    
    while (1) {
        printf("请输入访问的数据:\n");
        scanf("%d", &data);
        
        addCache(cache, data);
        
        printf("缓存的数据数据为:\n");
        for (i = 0; i < cache->length; i++) {
            Node *node = (Node *)cache->caches[i];
            
            printf("数据: %d\n", node->data);
            printf("时间戳: %d\n", node->num);
        }
    }
    
    return 0;
}

  1. 利用一个链表来实现,每次新插入数据时将新数据插到链表的头部:每次缓存命中(即数据被访问),则将数据移到链表头部;当链表满时,将链表尾部的数据丢弃。简单实现:
//
//  main.c
//  lru2
//
//  Created by 李龙 on 2018/12/10.
//  Copyright © 2018 李龙. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10
#define ERROR 0
#define SUCCESS 1

//结点
typedef struct Node {
    int data;           //数据
    struct Node *next;  //next指针
} Node;

//缓存数据
typedef struct {
    Node *node; //头结点
    int length; //长度
} Cache;

//判断是否有缓存, 若有缓存,将这个结点置到链头
int hasCache(Cache *cache, int data) {
    
    if (cache->length <= 0) {
        return ERROR;
    }
    
    //如果是首结点,则直接返回,不做任何操作
    if (cache->node->data == data) {
        return SUCCESS;
    }
    
    Node *node = cache->node;
    
    //记录前一个结点
    Node *pre = node;
    
    while (node) {
        if (node->data == data) {
            
            //前一个结点的next指向现结点的next
            pre->next = node->next;
            
            //记录当前头结点
            pre = cache->node;
            
            //将当前结点置为头结点
            node->next = pre;
            cache->node = node;
            
            return SUCCESS;
        } else {
            //记录前一个结点,指向下一个结点
            pre = node;
            node = node->next;
        }
    }
    
    return ERROR;
}

//添加缓存
void addCache(Cache *cache, int data) {

    //若有缓存,则将这个结点置为链头
    if (hasCache(cache, data) == SUCCESS) {
        
        //若没有缓存,添加进缓存
    } else {
        //创建结点,将结点置为链头
        Node *node = (Node *)malloc(sizeof(node));
        node->data = data;
        node->next = cache->node;
        cache->node = node;
        
        //若缓存没满,则length+1
        if (cache->length < MAXSIZE) {
            cache->length++;
            //若缓存满了,将最后一个结点删除
        } else {
            node = cache->node;
            
            for (int i = 0; i < MAXSIZE - 1; i++) {
                node = node->next;
            }
            node->next = NULL;
        }
    }
}

int main(int argc, const char * argv[]) {
    
    Cache *cache = (Cache *)malloc(sizeof(Cache));
    cache->length = 0;
    
    int i, data;
    
    while (1) {
        printf("请输入访问的数据:\n");
        scanf("%d", &data);
        
        addCache(cache, data);
        
        printf("缓存的数据数据为:\n");
        Node *node = cache->node;
        for (i = 0; i < cache->length; i++) {
            printf("数据: %d\n", node->data);
            node = node->next;
        }
        
    }
    return 0;
}
  1. 利用双向链表和hashmap来实现。访问数据时,通过哈希函数算出哈希值(注意解决冲突),从数组中取值,若没有,进行创建,添加进数组,并设置它为头结点。若存在,将它置为头结点。若缓存达到上限,删除记录的尾结点。使用哈希使其取值简单。简单实现:
//
//  main.c
//  lru3
//
//  Created by 李龙 on 2018/12/11.
//  Copyright © 2018 李龙. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10

//结点
typedef struct {
    int data;       //结点
    int pre;        //前一个数据下标
    int next;       //后一个数据下标
} Node;

//缓存
typedef struct {
    Node *caches[MAXSIZE * 2];  //哈希数组
    int start;              //头结点
    int end;                //尾结点
    int length;             //长度
} Cache;

//初始化缓存列表
Cache * creatCaches() {
    
    Cache *cache = (Cache *)malloc(sizeof(Cache));
    cache->length = 0;
    //设置首尾结点尾-1
    cache->start = -1;
    cache->end = -1;
    for (int i = 0; i < MAXSIZE * 2; i++) {
        cache->caches[i] = NULL;
    }
    
    return cache;
}

//算取哈希值,使用除余法
int hashData(Cache *hashCache, int data, int *indexNode) {
    
    int index = data % (MAXSIZE * 2);
    //判断该位置是否有值
    while (hashCache->caches[index] != NULL) {
        //有值
        Node *node = hashCache->caches[index];
        //若跟值相同,则进行记录这个位置,并返回-1标记为有值
        if (node->data == data) {
            *indexNode = index;
            return -1;
        }
        
        //若不相同,则冲突处理
        index++;
        index = index % (MAXSIZE * 2);
    }
    
    return index;
}

//删除结点
void deleteHashCache(Cache *hashCache) {
    
    //获取尾结点坐标
    int end = hashCache->end;
    //尾结点
    Node *node = hashCache->caches[end];
    //尾结点前一个结点坐标
    int pre = node->pre;
    node = hashCache->caches[pre];
    //置为-1
    node->next = -1;
    
    //尾结点
    hashCache->end = pre;
    //删除结点, 释放指针
    free(node);
    
}

//添加缓存
void addHashCache(Cache *hashCache, int data) {
    
    //记录相同值位置
    int indexNode;
    
    //取哈希值
    int index = hashData(hashCache, data, &indexNode);
    
    //若有相同值
    if (index == -1) {
        
        Node *node = hashCache->caches[indexNode];
        
        //设置该点为头结点,若为尾结点,则将尾结点前一个结点置为缓存尾结点
        if (indexNode == hashCache->end && hashCache->length != 1) {
            hashCache->end = node->pre;
        }
        
        //若不为头结点,将它前一个结点的next指向它的next
        if (node->pre != -1) {
            Node *preNode = hashCache->caches[node->pre];
            preNode->next = node->next;
        }
        
        //若不为尾结点,将它后一个结点的pre指向它的pre
        if (node->next != -1) {
            Node *nextNode = hashCache->caches[node->next];
            nextNode->pre = node->pre;
        }
        
        //拿到头结点,将头结点pre指向它
        Node *startNode = hashCache->caches[hashCache->start];
        startNode->pre = indexNode;
        
        //它的pre指向-1
        node->pre = -1;

        //若它不为头结点,将它的next指向头结点
        if (indexNode != hashCache->start) {
            node->next = hashCache->start;
        }
        //设置它为头结点
        hashCache->start = indexNode;
        
        //只有一个结点,置next为-1
        if (hashCache->length == 1) {
            node->next = -1;
        }
        
       //若无缓存值
    } else {
        
        //没有到最大缓存数,长度+1
        if (hashCache->length < MAXSIZE) {
            hashCache->length++;
        } else {
            //删除尾结点
            deleteHashCache(hashCache);
        }
        
        //创建新结点
        Node *node = (Node *)malloc(sizeof(Node));
        node->data = data;
        //头结点pre为-1
        node->pre = -1;
        node->next = hashCache->start;
        hashCache->caches[index] = node;
        
        //若有值
        if (hashCache->start != -1) {
            //头结点的pre置为它
            Node *startNode = hashCache->caches[hashCache->start];
            startNode->pre = index;
        }
        //记录头结点
        hashCache->start = index;
        
        //记录尾结点
        if (hashCache->length == 1) {
            hashCache->end = index;
        }
    }
    
}


int main() {
    
    Cache *hashCache = creatCaches();
    
    int i, data;
    
    while (1) {
        printf("请输入访问的数据:\n");
        scanf("%d", &data);
        
        addHashCache(hashCache, data);
        
        printf("缓存的数据数据为:\n");
        
        int index = hashCache->start;
        printf("首结点坐标为:%d\n", hashCache->start);
        for (i = 0; i < hashCache->length; i++) {
            Node *node = hashCache->caches[index];
            printf("数据为:%d   上一个坐标为:%d   下一个坐标为:%d\n", node->data, node->pre, node->next);
            index = node->next;
        }
        printf("尾结点坐标为:%d\n", hashCache->end);
        
    }
    
    return 0;
}

实现相对来说有点复杂,而且可能还会有bug,但实现思路大概就是这个样子。
第三种方法是现阶段,一般使用的LRU算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值