双向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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值