NO.146 LRU缓存机制

博客介绍运用数据结构设计和实现LRU(最近最少使用)缓存机制,支持获取数据get和写入数据put操作。当缓存容量达上限时,写入新数据前会删除最近最少使用的数据。还探讨能否在O(1)时间复杂度完成操作,并给出示例及C语言实现的执行情况。

运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

进阶:

你是否可以在 O(1) 时间复杂度内完成这两种操作?

示例:

LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回  1
cache.put(3, 3);    // 该操作会使得密钥 2 作废
cache.get(2);       // 返回 -1 (未找到)
cache.put(4, 4);    // 该操作会使得密钥 1 作废
cache.get(1);       // 返回 -1 (未找到)
cache.get(3);       // 返回  3
cache.get(4);       // 返回  4

struct Double_list;
struct Hash_table{
   int key;
   int value;
   struct Double_list *list_pos;
   //同一hash用链表解决冲突
   struct Hash_table *next_entry;
};
struct Double_list{
   struct Hash_table *hash;
   struct Double_list *previous;
   struct Double_list *next;
};
typedef struct {
   int table_size;
   int total_entry;
   struct Hash_table **hash_table;//桶大小由table_size决定
   struct Double_list *head;
    struct Double_list *end;
} LRUCache;
static inline int get_hash(int key)
{
   return (key<<16)+(key<<8)+key;
}
void show(struct Double_list * copy)
{
    printf("\n|-");
    while(copy)
    {
        printf("%d-",copy->hash->key);
        copy=copy->next;
    }
    printf("|\n");
}
LRUCache* lRUCacheCreate(int capacity) {
   assert(capacity>0);
   LRUCache* ret=(LRUCache*)malloc(sizeof(LRUCache));
   ret->table_size=capacity;
   ret->hash_table=(struct Hash_table * *)calloc(ret->table_size,sizeof(struct Hash_table *));
   ret->total_entry=0;
   ret->head=NULL;
   ret->end=NULL;
   return ret;
}

int lRUCacheGet(LRUCache* obj, int key) {
   int ret=-1;
   struct Hash_table * hash=obj->hash_table[get_hash(key)%obj->table_size];
   while(hash)
   {
       if(hash->key==key)
       {
           ret=hash->value;
           if(hash->list_pos->previous&&hash->list_pos->next)
           {
               hash->list_pos->previous->next=hash->list_pos->next;
               hash->list_pos->next->previous=hash->list_pos->previous;
               hash->list_pos->previous=NULL;
               hash->list_pos->next=obj->head;
               obj->head->previous=hash->list_pos;
               obj->head=hash->list_pos;
           }
           else if(!hash->list_pos->previous)
           {//为头节点,无需移动

           }
           else
           {//为尾部节点
               obj->end=obj->end->previous;
               obj->end->next=NULL;
               hash->list_pos->next=obj->head;
               hash->list_pos->previous=NULL;
               obj->head->previous=hash->list_pos;
               obj->head=hash->list_pos;
           }
       }
       hash=hash->next_entry;
   }
    //show(obj->head);
   return ret;
}

void lRUCachePut(LRUCache* obj, int key, int value) {
   int hash_key=get_hash(key)%obj->table_size;
   if(lRUCacheGet(obj,key)!=(-1))
   {
       struct Hash_table *tmp=obj->hash_table[hash_key];
       while(tmp)
       {
           if(tmp->key==key)
           {
               tmp->value=value;
               break;
           }
           tmp=tmp->next_entry;
       }
       return;
   }
   if(obj->total_entry>=obj->table_size)
   {//桶满,需删除元素
       int erase_key=obj->end->hash->key;
       struct Hash_table * hash=obj->hash_table[get_hash(erase_key)%obj->table_size];
       struct Hash_table * tmp=NULL;
       while(hash)
       {//从hash表中移除
           if(hash->key==erase_key)
           {
               tmp=hash;
               obj->hash_table[get_hash(erase_key)%obj->table_size]=hash->next_entry;
               break;
           }
           if(hash->next_entry->key==erase_key)
           {
               tmp=hash->next_entry;
               hash->next_entry=hash->next_entry->next_entry;
               break;
           }
           hash=hash->next_entry;
       }
       //从访问双向链表中移除
       if(tmp->list_pos->previous)
       {
           obj->end=tmp->list_pos->previous;
           obj->end->next=NULL;
           free(tmp->list_pos);
           free(tmp);
       }
       else
       {
           obj->end=NULL;
           obj->head=NULL;
       }
       obj->total_entry--;
   }
   obj->total_entry++;
   struct Hash_table * new_entry=(struct Hash_table *)malloc(sizeof(struct Hash_table));
   new_entry->key=key;
   new_entry->value=value;
   new_entry->next_entry=NULL;
   new_entry->list_pos=(struct Double_list*)malloc(sizeof (struct Double_list));
    new_entry->list_pos->hash=new_entry;
   //加入访问链表头部
   new_entry->list_pos->previous=NULL;
   new_entry->list_pos->next=obj->head;
   if(obj->head)obj->head->previous=new_entry->list_pos;
   if(!obj->end)obj->end=new_entry->list_pos;
   obj->head=new_entry->list_pos;
   //插入至hash表
   struct Hash_table * hash=obj->hash_table[hash_key];
   if(!hash)obj->hash_table[hash_key]=new_entry;
   else
   {
       while(hash->next_entry!=NULL)hash=hash->next_entry;
       hash->next_entry=new_entry;
   }
     //show(obj->head);
}

void lRUCacheFree(LRUCache* obj) {
   free(obj->hash_table);
   struct Hash_table * hash=NULL;
   struct Double_list * tmp=NULL;
   while(obj->head)
   {
       tmp=obj->head;
       obj->head=obj->head->next;
       hash=tmp->hash;
       free(tmp);
       free(hash);
   }
   free(obj);
}

/**
* Your LRUCache struct will be instantiated and called as such:
* LRUCache* obj = lRUCacheCreate(capacity);
* int param_1 = lRUCacheGet(obj, key);

* lRUCachePut(obj, key, value);

* lRUCacheFree(obj);
*/

执行用时 :116 ms, 在所有 C 提交中击败了90.74% 的用户

内存消耗 :26.6 MB, 在所有 C 提交中击败了50.00%的用户

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值