参考自: https://github.com/Stand1210/c-LRU-/blob/master/LRU/lru_cache_impl.c 感谢博主,代码非常干净漂亮,学到很多。
typedef struct cacheEntryS {
int key; /* 数据的key */
int value; /* 数据的data */
struct cacheEntryS* hashListPrev; /* 缓存哈希表指针, 指向哈希链表的前一个元素 */
struct cacheEntryS* hashListNext; /* 缓存哈希表指针, 指向哈希链表的后一个元素 */
struct cacheEntryS* lruListPrev; /* 缓存双向链表指针, 指向链表的前一个元素 */
struct cacheEntryS* lruListNext; /* 缓存双向链表指针, 指向链表后一个元素 */
}cacheEntryS;
typedef struct LRUCache{
int lruListSize; /*缓存的双向链表节点个数*/
int cacheCapacity; /*缓存的容量*/
cacheEntryS** hashMap; /*缓存的哈希表*/
cacheEntryS* lruListHead; /*缓存的双向链表表头*/
cacheEntryS* lruListTail; /*缓存的双向链表表尾*/
} LRUCache;
static unsigned int hashKey(LRUCache* cache, int key)
{
unsigned int a = 63689;
unsigned int hash = 31;
unsigned int i = 0;
hash = hash * a + key;
return hash % (cache->cacheCapacity);
}
LRUCache* lRUCacheCreate(int capacity) {
LRUCache* obj = malloc(sizeof(*obj));
if (obj == NULL)return NULL;
memset(obj, 0, sizeof(LRUCache*));
obj->cacheCapacity = capacity;
obj->hashMap = malloc(sizeof(cacheEntryS*)*capacity);
if (obj->hashMap == NULL) {
free(obj);
return NULL;
}
obj->lruListSize = 0;
obj->lruListHead = obj->lruListTail = NULL;
memset(obj->hashMap, 0, sizeof(cacheEntryS*) * capacity);
return obj;
}
static cacheEntryS* newCacheEntry(int key, int value) {
cacheEntryS* en = malloc(sizeof(*en));
if (en == NULL) { perror("malloc"); return NULL; }
memset(en, 0, sizeof(*en));
en->key = key;
en->value = value;
en->lruListNext = NULL;
en->lruListPrev = NULL;
en->hashListNext = NULL;
en->hashListPrev = NULL;
return en;
}
static cacheEntryS* getValueFromHashMap(LRUCache* cache, int key) {
cacheEntryS* en = cache->hashMap[hashKey(cache, key)];
while (en) {
if (en->key == key)break;
en = en->hashListNext;
}
return en;
}
static void insertentryToHashMap(LRUCache* cache, cacheEntryS* entry) {
cacheEntryS* en = cache->hashMap[hashKey(cache, entry->key)];
if (en != NULL) {
entry->hashListNext = en;
en->hashListPrev = entry;
}
cache->hashMap[hashKey(cache, entry->key)] = entry;
}
static void removeEntryFromHashMap(LRUCache* cache, cacheEntryS* entry)
{
int key = entry->key;
cacheEntryS *en = cache->hashMap[hashKey(cache, key)];
if (en == NULL||cache==NULL||entry==NULL)return;
while (en) {
if (en->key == key) {
if (en->hashListPrev)en->hashListPrev->hashListNext = en->hashListNext;
else cache->hashMap[hashKey(cache, key)] = en->hashListNext;
if (en->hashListNext) {
en->hashListNext->hashListPrev = en->hashListPrev;
}
return;
}
en = en->hashListNext;
}
}
/*list operation*/
static void removeFromList(LRUCache* cache, cacheEntryS* entry) {
if (cache->lruListSize == 0) {
return;
}
if (entry == cache->lruListHead && entry == cache->lruListTail) {
cache->lruListHead = cache->lruListTail = NULL;
}
else if (entry == cache->lruListHead) {
cache->lruListHead = entry->lruListNext;
cache->lruListHead->lruListPrev = NULL;
}
else if (entry == cache->lruListTail) {
cache->lruListTail=entry->lruListPrev;
cache->lruListTail->lruListNext = NULL;
}
else {
entry->lruListPrev->lruListNext = entry->lruListNext;
entry->lruListNext->lruListPrev = entry->lruListPrev;
}
cache->lruListSize--;
}
static cacheEntryS* insertToListHead(LRUCache* obj, cacheEntryS* entry) {
LRUCache*cache=obj;
++cache->lruListSize;
cacheEntryS* removedEntry = NULL;
if (cache->lruListSize >cache->cacheCapacity) {
removedEntry = cache->lruListTail;
removeFromList(cache, cache->lruListTail);
}
if (cache->lruListHead == NULL&&cache->lruListTail==NULL) {
cache->lruListHead =cache->lruListTail= entry;
}
else {
entry->lruListNext=cache->lruListHead;
entry->lruListPrev = NULL;
cache->lruListHead->lruListPrev = entry;
cache->lruListHead = entry;
}
return removedEntry;
}
static void freeList(LRUCache* cache) {
if (cache->lruListSize == 0)return;
cacheEntryS* p = cache->lruListHead;
while (p) {
cacheEntryS* temp = p->lruListNext;
free(p);
p = temp;
}
cache->lruListSize = 0;
}
static void updateLRUList(LRUCache* cache, cacheEntryS* entry)
{
/*将节点从链表中摘抄*/
removeFromList(cache, entry);
/*将节点插入链表表头*/
insertToListHead(cache, entry);
}
int lRUCacheGet(LRUCache* obj, int key) {
LRUCache* cache = obj;
cacheEntryS* entry = getValueFromHashMap(cache, key);
if (entry == NULL)return -1;
else {
updateLRUList(cache, entry);
return entry->value;
}
}
void lRUCachePut(LRUCache* obj, int key, int value) {
LRUCache* cache = obj;
cacheEntryS*entry= newCacheEntry(key, value);
cacheEntryS* en = getValueFromHashMap(cache, key);
if (en != NULL) {
en->value = value;
updateLRUList(cache, en);
}else{
cacheEntryS* removedentry=insertToListHead(cache, entry);
if (removedentry!=NULL) {
removeEntryFromHashMap(cache, removedentry);
free(removedentry);
}
insertentryToHashMap(cache, entry);
}
return;
}
void lRUCacheFree(LRUCache* obj) {
LRUCache* cache = obj;
if (cache == NULL)return 0;
if (cache->hashMap)free(cache->hashMap);
freeList(cache);
free(cache);
}