首页 > 试题广场 >

设计LRU缓存结构

[编程题]设计LRU缓存结构
  • 热度指数:144640 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 k ,操作次数是 n ,并有如下两个功能
1. set(key, value):将记录(key, value)插入该结构
2. get(key):返回key对应的value值

提示:
1.某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的,然后都会刷新缓存。
2.当缓存的大小超过k时,移除最不经常使用的记录。
3.输入一个二维数组与k,二维数组每一维有2个或者3个数字,第1个数字为opt,第2,3个数字为key,value
若opt=1,接下来两个整数key, value,表示set(key, value)
若opt=2,接下来一个整数key,表示get(key),若key未出现过或已被移除,则返回-1
对于每个opt=2,输出一个答案
4.为了方便区分缓存里key与value,下面说明的缓存里key用""号包裹

要求:set和get操作复杂度均为
数据范围:
示例1

输入

[[1,1,1],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]],3

输出

[1,-1]

说明

[1,1,1],第一个1表示opt=1,要set(1,1),即将(1,1)插入缓存,缓存是{"1"=1}
[1,2,2],第一个1表示opt=1,要set(2,2),即将(2,2)插入缓存,缓存是{"1"=1,"2"=2}
[1,3,2],第一个1表示opt=1,要set(3,2),即将(3,2)插入缓存,缓存是{"1"=1,"2"=2,"3"=2}
[2,1],第一个2表示opt=2,要get(1),返回是[1],因为get(1)操作,缓存更新,缓存是{"2"=2,"3"=2,"1"=1}
[1,4,4],第一个1表示opt=1,要set(4,4),即将(4,4)插入缓存,但是缓存已经达到最大容量3,移除最不经常使用的{"2"=2},插入{"4"=4},缓存是{"3"=2,"1"=1,"4"=4}
[2,2],第一个2表示opt=2,要get(2),查找不到,返回是[1,-1]        
示例2

输入

[[1,1,1],[1,2,2],[2,1],[1,3,3],[2,2],[1,4,4],[2,1],[2,3],[2,4]],2

输出

[1,-1,-1,3,4]

题解 | [C语言]设计LRU缓存结构

参考下吧,没有链表,纯数组操作
/**
 * lru design
 * @param operators int整型二维数组 the ops
 * @param operatorsRowLen int operators数组行数
 * @param operatorsColLen int* operators数组列数
 * @param k int整型 the k
 * @return int整型一维数组
 * @return int* returnSize 返回数组行数
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */
#define BUF_LEN 100000
static int lrubuf[BUF_LEN];
static int lrubufindex = 0;
static int returnbuf[BUF_LEN];
static int returnindex = 0;
static int keyindex = 0;
#define  min(x,y)   ((x)<=(y)?(x):(y))
void setval(int *buf, int key )
{
    int i = 0;
    int tempkey = 0;
    int keyval = min(key,keyindex);
    for(;i<keyval;i++)
    {
        if(*(buf+1) == lrubuf[2*i])
            break;
    }
    if(i != keyval)
    {
        memmove(&lrubuf[2*i],&lrubuf[2*(i+1)],(keyval - i - 1) * 8);
        lrubuf[2*keyval - 2] = *(buf +1);
        lrubuf[2*keyval -1] = *(buf + 2);
    }
    
    if(keyindex < key)
    {
        
    }
    else
    {
        memmove(lrubuf,&lrubuf[2],(key - 1) * 8);
        lrubufindex -= 2;
    }
    lrubuf[lrubufindex++] = *(buf + 1);
    lrubuf[lrubufindex++] = *(buf + 2);
    i++;
}
void getval(int *buf, int key)
{
    int i = 0;
    int res = -1;
    int temp[2];
    int keyval = min(key,keyindex);
    for(i = 0;i < keyval ; i ++)
    {
        if(lrubuf[2*i] == *(buf+1))
        {
            temp[0] = lrubuf[2*i];
            temp[1] = res = lrubuf[2*i + 1];
            
            memmove(&lrubuf[2*i],&lrubuf[2*(i+1)],(keyval - i - 1) * 8);
            lrubuf[2*keyval - 2] = temp[0];
            lrubuf[2*keyval -1] = temp[1];
            
            break;
        }
        else
            res = -1;
    }
    returnbuf[returnindex] = res;
    returnindex ++;
}

int* LRU(int** operators, int operatorsRowLen, int* operatorsColLen, int k, int* returnSize ) {
    // write code here
    for(int i = 0;i < operatorsRowLen; i ++)
    {
        if(** (operators + i) == 1)
        {
            setval(*(operators + i), k );
            keyindex ++;
        }
        else if(** (operators + i) == 2)
        {
            getval(*(operators + i), k);
        }
    }
    *returnSize = returnindex;
    return returnbuf;
}


发表于 2021-12-21 21:59:56 回复(2)
//1.创建链表首尾节点,首尾节点不参与数据的存储,存储数据需要在首尾节点之间创建新的链表节点;
//2.降维数据的原始数据,读取每个数组的第一个元素opt,根据opt值选择Set or Get函数;
//3.Set函数处理以下两个问题:
//检测是否存在KEY,如果存在,移动节点至第一个有效链表节点;
//如果不存在KEY,判断缓存器的有效个数是否达到最大值K,如果达到最大值K,需要删除最后一个节点;然后再创建新的节点,插入第一个有效节点处;
//4.Get函数,检测是否存在KEY,如果存在,返回对应的value,移动至第一个有效节点处,否则返回-1;
struct Lru_node {     int key;     int value;     struct Lru_node* prev;     struct Lru_node* next; }; static int Len_K = 0; static int ListnodeLen = 0; static struct Lru_node* Head = NULL; static struct Lru_node* Tail = NULL; void Initial_Node(void)//初始化,创建首尾节点,该首尾节点不参与存储缓存器数据 {     Head = (struct Lru_node*)malloc(sizeof(struct Lru_node));     Head->key = 0;     Head->value = 0;     Head->prev = NULL;     Head->next = NULL;     Tail = (struct Lru_node*)malloc(sizeof(struct Lru_node));     Tail->key = 0;     Tail->value = 0;     Tail->prev = NULL;     Tail->next = NULL;     Head->next = Tail;     Tail->prev = Head; } void Delete_End()//删除最后一个节点 {     struct Lru_node*Delete_Temp = NULL;     Delete_Temp = Tail->prev;     Tail->prev->prev->next = Tail;     Tail->prev = Tail->prev->prev;     free(Delete_Temp);     ListnodeLen--; } void Insert_Head(int key, int value)//创建新的节点,并将该节点添加至缓存器的第一个有效节点位置 {     struct Lru_node*NewNode = NULL;     if(ListnodeLen == Len_K) //检查缓存器的当前节点数量是否达到设定的最大值K     {         Delete_End();//如果节点数达到最大值K,则需要删除最后一个节点     }     NewNode = (struct Lru_node*)malloc(sizeof(struct Lru_node));//创建新的节点     NewNode->key = key;     NewNode->value = value;     NewNode->prev = Head;     NewNode->next = Head->next;     Head->next->prev = NewNode;     Head->next = NewNode;     //Head = NewNode;     ListnodeLen++; } void Move_Head(struct Lru_node*Move_node)//移动当前节点至缓存器第一个有效节点 {     Move_node->prev->next = Move_node->next;     Move_node->next->prev = Move_node->prev;     Move_node->prev = Head;     Move_node->next = Head->next;     Head->next->prev = Move_node;     Head->next = Move_node;     //Head = Move_node; } void Set(int key, int value) //Set函数,如果KEY存在,刷新该节点至缓存器的第一个单元,否则增加新的节点至第一个有效存储单元位置 {     struct Lru_node* Set_temp = NULL;     Set_temp = Head->next;  //缓存器第一个存储单元     while(Set_temp->next != NULL)//查询缓存器元素KEY     {         if(Set_temp->key == key)         {             Move_Head(Set_temp);//KEY存在,刷新该节点至缓存器的第一个单元             break;         }         Set_temp = Set_temp->next;     }     if(Set_temp->next == NULL)     {         Insert_Head(key,value);//KEY不存在,创建新的节点至缓存器的第一个单元     } } int Get(int key)  //Get函数实现,判断缓存器是否存在KEY,如果有返回value,否则返回-1 {     struct Lru_node* Get_temp = NULL;     Get_temp = Head->next; //缓存器第一个存储单元     int returnVlaue =0;     while(Get_temp->next != NULL)  //查询缓存器元素KEY     {         if (Get_temp->key == key)         {             Move_Head(Get_temp);  //查找到Key后,刷新至缓存器第一个有效存储单元             returnVlaue = Get_temp->value; //返回对应的value值             break;         }         Get_temp = Get_temp->next;     }     if(Get_temp->next == NULL)     {         returnVlaue = -1; //未查找到Key后,返回-1     }     return returnVlaue; } int* LRU(int** operators, int operatorsRowLen, int* operatorsColLen, int k, int* returnSize ) {     // write code here     int*ope_arry = NULL;  //读取数组数据     int*return_arry = NULL; //当OPT=2时,返回数据春初数组     *returnSize = 0;   //返回数据数组元素个数     Len_K = k;   //全局变量,春初当前缓存器中的有效数据个数     Initial_Node();  //初始化函数,生成链表的头节点以及尾节点     for(int i=0;i < operatorsRowLen; i++) //降维读物输入数组     {         ope_arry = operators[i];         if(ope_arry[0]==1)  //判断OPT = 1          {             Set(ope_arry[1],ope_arry[2]);    //执行Set函数         }         else if(ope_arry[0]==2)  //判断OPT = 2         {             *returnSize = *returnSize +1;  //返回数据数组元素个数增加1             return_arry = (int *)realloc(return_arry, (*returnSize) * sizeof(int));//刷新数组内存空间             return_arry[*returnSize-1] = Get(ope_arry[1]);//执行Get函数,并将返回值存入返回值数组         }     }     return return_arry; }

发表于 2021-10-19 20:25:19 回复(0)