双向LRU链表

LRU是最近最少使用算法。一般内存管理的时候采用LRU算法可以提高性能。

将cache缓存块位置用LRU双向链表链接起来,将新加入的块直接放到链表的头,当一个块被命中后,把该块调整到链表的头,这样经过多次操作之后,最近被命中过的块就会向链表头部移动,而没有被命中的内容会向链表尾部移动,需要替换时,就直接从链表尾部替换即可。新的内容直接插入链表头部,这样就实现了LRU的思想。

算法中维护了一个freelist,用于管理空闲块的位置,每次需要插入新的内容时,就从freelist里面获取一个空闲块,将新内容复制,然后插入到链表头部;删除时就从链表尾部删除结点,然后更新到freelist里;查找一个结点时,在一般链表中的时间复杂度是O(n),为了提高查找效率,在算法中加入了一个hash表,每次新加入的结点都会更新到hash表里,删除结点时会从hash表中移除,这样查找的时候直接从hash表里查询,获取结点的位置,从而时间复杂度为O(1)。

C语言实现的代码如下(已经测试通过了):

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
 
#define LRU_SIZE 20
#define HASH_BASE 20
#define LRU_SUCCESS 0
#define LRU_ERROR  -1
#define LRU_MISS 0
#define LRU_HIT 1
#define LRU_HASH_KEY(_key,_base)               (int)(((int)_key)%(_base))
 
typedef struct _LRU_NODE{
         int id;
         int key;
         int free;
         int prev;
         int next;
}LRU_NODE,*PLRU_NODE;
typedef struct _LRU_HASH{
    unsigned long   basesize;
    int base[HASH_BASE];
}LRU_HASH,*PLRU_HASH;
 
typedef struct _LRU_LIST{
         int capacity;
         int usage;
         LRU_NODE bucket[LRU_SIZE];
         int freelist;
         int head;
         int tail;
         LRU_HASH hash;
}LRU_LIST,*PLRU_LIST;
 
int lru_init(PLRU_LIST list, int capacity, int hashbase)
{
         int i;
         PLRU_NODE node;
         list->capacity = capacity;
         list->usage = 0;
         list->head = -1;
         list->tail = -1;
         list->freelist = -1;
         for(i = capacity - 1; i >= 0; i--)
         {
                   list->bucket[i].id = i;
                   list->bucket[i].key = -1;
                   list->bucket[i].free = 1;
                   list->bucket[i].prev = -1;
                   list->bucket[i].next = -1;
                   if(list->freelist == -1)
                   {
                            list->freelist = list->bucket[i].id;
                   }
                   else
                   {
                            node = &(list->bucket[list->freelist]);
                            node->prev = list->bucket[i].id;
                            list->bucket[i].next = node->id;
                            list->freelist = list->bucket[i].id;
                   }
         }
         for(i = 0; i < hashbase; i++)
         {
                   list->hash.base[i] = -1;
         }
         list->hash.basesize = hashbase;
         return LRU_SUCCESS;
}
int lru_sethead(PLRU_LIST list, PLRU_NODE node)
{
         PLRU_NODE tempnode;
         if(node->free)
                   return LRU_SUCCESS;
         if(node->id == list->head)
                   return LRU_SUCCESS;
         if(list->head == -1)
         {
                   //应该不会到这里面来 
                   list->head = node->id;
                   list->tail = node->id;
                   node->prev = -1;
                   node->next = -1;
         }
         else
         {
                   if(list->tail == node->id)
                   {
                            list->tail = node->prev;
                            tempnode = &(list->bucket[list->tail]);
                            tempnode->next = -1;
                            
                   }
                   else 
                   {
                            tempnode = &(list->bucket[node->prev]);
                            tempnode->next = node->next;
                            tempnode = &(list->bucket[node->next]);
                            tempnode->prev = node->prev;
                   }
                   tempnode = &(list->bucket[list->head]);
                   tempnode->prev = node->id;
                   node->next = list->head;
                   node->prev = -1;
                   list->head = node->id;
         }
         return LRU_SUCCESS;
}
int lru_getfree(PLRU_LIST list, PLRU_NODE *freenode)
{
         PLRU_NODE node = NULL;
         if(list->freelist != -1)
         {
                   node = &(list->bucket[list->freelist]);
                   list->freelist = node->next;
                   if(list->freelist != -1)
                   {
                            list->bucket[list->freelist].prev = -1;
                   }
                   node->free = 1;
                   *freenode = node;
                   return LRU_SUCCESS;
         }
         else
         {
                   *freenode = NULL;
                   return LRU_ERROR;
         }
}
/*lru_delete:delete tail lru node
list:lru list
*/
int lru_delete(PLRU_LIST list)
{
         PLRU_NODE tempnode;
         int hashkey;
         if(list->tail == -1)
                   return LRU_ERROR;
         tempnode = &(list->bucket[list->tail]);
         list->tail = tempnode->prev;
         if(list->tail != -1)
                   list->bucket[list->tail].next = -1;
         else
                   list->head = -1;
 
         //删除hash结点
         hashkey = LRU_HASH_KEY(tempnode->key, list->hash.basesize);
         list->hash.base[hashkey] = -1;
         
         if(list->freelist != -1)
         {
                   tempnode->next = list->freelist;
                   list->bucket[list->freelist].prev = tempnode->id;
                   list->freelist = tempnode->id;
                   tempnode->prev = -1;
                   tempnode->free = 1;
                   tempnode->key = -1;
         }
         else
         {
                   list->freelist = tempnode->id;
                   tempnode->key = -1;
                   tempnode->free = 1;
                   tempnode->prev = -1;
                   tempnode->next = -1;
         }
         list->usage--;
         return LRU_SUCCESS;
}
int lru_insert(PLRU_LIST list, PLRU_NODE node)
{
         //对于list满的情况和插入有相同key的node
         //在函数调用之前作判断
         PLRU_NODE tempnode;
         int key;
         int hashkey;
         //插入lru hash表
         key = node->key;
         hashkey = LRU_HASH_KEY(key, list->hash.basesize);
         list->hash.base[hashkey] = node->id;
         
         if(list->head == -1)
         {
                   list->head = node->id;
                   list->tail = node->id;
                   node->prev = -1;
                   node->next = -1;
         }
         else
         {
                   tempnode = &(list->bucket[list->head]);
                   node->next = list->head;
                   tempnode->prev = node->id;
                   list->head = node->id;
                   node->prev = -1;
         }
         node->free = 0;
         list->usage++;
         return LRU_SUCCESS;
}
int lru_inquiry(PLRU_LIST list, int key)
{
         PLRU_NODE tempnode;
         int hashkey;
         if(list->head == -1)
                   return LRU_MISS;
 
         hashkey = LRU_HASH_KEY(key, list->hash.basesize);
         if(list->hash.base[hashkey] == -1)
                   return LRU_MISS;
         else
         {
                   tempnode = &(list->bucket[list->hash.base[hashkey]]);
         }
         //没加lru hash表之前的查询方式
         /*tempnode = &(list->bucket[list->head]);
         while(tempnode && tempnode->key != key)
         {
                   if(tempnode->next == -1)
                            tempnode = NULL;
                   else
                            tempnode = &(list->bucket[tempnode->next]);
         }
         if(!tempnode)
                   return LRU_MISS;*/
         lru_sethead(list,tempnode);
         return LRU_HIT;
}
int lru_show(PLRU_LIST list)
{
         PLRU_NODE node;
         if(list->head == -1)
         {
                   printf("list is empty!\n");
                   return LRU_ERROR;
         }
         node = &(list->bucket[list->head]);
         while(node)
         {
                   printf("id:%d,key:%d\n", node->id, node->key);
                   if(node->next == -1)
                            node = NULL;
                   else
                            node = &(list->bucket[node->next]);
         }
         return LRU_SUCCESS;
}
int lru_clear(PLRU_LIST list)
{
         PLRU_NODE tempnode,node;
         unsigned long j;
         if(list->head == -1)
                   return LRU_SUCCESS;
         tempnode = &(list->bucket[list->head]);
         while(tempnode)
         {
                   if(tempnode->next == -1)
                            node = NULL;
                   else
                            node = &(list->bucket[tempnode->next]);
                   if(list->freelist == -1)
                   {
                            list->freelist = tempnode->id;
                            tempnode->free = 1;
                            tempnode->key = -1;
                            tempnode->next = -1;
                            tempnode->prev = -1;
                   }
                   else
                   {
                            tempnode->next = list->freelist;
                            list->bucket[list->freelist].prev = tempnode->id;
                            list->freelist = tempnode->id;
                            tempnode->prev = -1;
                            tempnode->key = -1;
                            tempnode->free = 1;
                   }
                   tempnode = node;
         }
         for(j = 0; j < list->hash.basesize; j++)
         {
                   list->hash.base[j] = -1;
         }
         list->head = -1;
         list->tail = -1;
         list->usage = 0;
         return LRU_SUCCESS; 
}
 
void main()
{
         int key_table[LRU_SIZE];
         int i, usage;
         PLRU_LIST list;
         PLRU_NODE node;
         srand(time(NULL));
         for(i = 0; i < LRU_SIZE; i++)
         {
                   key_table[i] = rand() % LRU_SIZE;
                   printf("key_table[%d]:%d\n", i, key_table[i]);
         }
         list = (PLRU_LIST)malloc(sizeof(LRU_LIST));
         if(!list)
                   printf("malloc error!\n");
         lru_init(list, LRU_SIZE, HASH_BASE);
         //node = (PLRU_NODE)malloc(sizeof(LRU_NODE));
         //if(!node)
                   //printf("malloc error!\n");
         for(i = 0; i < LRU_SIZE; i++)
         {
                   if(LRU_MISS == lru_inquiry(list, key_table[i]))
                   {
                   if(LRU_SUCCESS == lru_getfree(list, &node))
                   {
                            node->key =key_table[i];
                            lru_insert(list, node);
                   }
                   else
                   {
                            printf("lru_getfree:get no free node!\n");
                   }
                   }
                   else
                   {
                            printf("***************\n");
                            printf("lru_inquiry hit key_table[%d]:%d\n", i, key_table[i]);
                            lru_show(list);
                   }
         }
         lru_show(list);
         usage = list->usage;
         for(i = 0; i < usage; i++)
         {
                   lru_delete(list);
                   printf("after delete one node!\n");
                   lru_show(list);
         }
         lru_clear(list);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值