/* * file name: LRUCache.h * desp: LRU缓存接口 */ #ifndef __LRUCACHE_H__ #define __LRUCACHE_H__ int LRUCacheCreate(int capacity, void **lruCache); int LRUCacheDestroy(void *lruCache); int LRUCacheSet(void *lruCache, char key, char data); char LRUCacheGet(void *lruCache, char key); void LRUCachePrint(void *lruCache); #endif
头文件描述
/* LRUCacheImpl.h 定义LRU缓存内部数据结构 */ #ifndef __LRUCACHEIMPL_H__ #define __LRUCACHEIMPL_H__ /*定义LRU缓存的缓存单元*/ typedef struct cacheEntryS { char key; char data; struct cacheEntryS *hashListPrev; /* 缓存哈希表指针,指向哈希链表的前一个元素 */ struct cacheEntryS *hashListNext; /* 缓存哈希表指针,指向哈希链表的后一个元素 */ struct cacheEntryS *lruListPrev; /* 缓存双向链表,指向双向链表的前一个元素 */ struct cacheEntryS *lruListNext; /* 缓存双向链表,指向双向链表的后一个元素 */ }cacheEntryS; typedef struct LRUCacheS { int cacheCapacity; cacheEntryS **hashMap; //缓存的hash表 cacheEntryS *lruListHead; //缓存双向链表的表头 cacheEntryS *lruListTail; //缓存双向链表表位 int lruListSize; //缓存双向链表节点个数 }LRUCacheS; #endif
相关函数介绍
/* LRUCacheImpl.c */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include"LRUCache.h" #include"LRUCacheImpl.h" static void freeList(LRUCacheS *cache); /**************************************************** *LRU缓存及缓存单位相关接口及实现 *****************************************************/ //创建一个缓存单位 static cacheEntryS *newCacheEntry(char key, char data) { cacheEntryS* entry = NULL; if (NULL == (entry = malloc(sizeof(*entry)))) { perror("malloc"); return NULL; } memset(entry, 0, sizeof(*entry)); entry->key = key; entry->data = data; return entry; } //释放一个缓存单元 static void freeCacheEntry(cacheEntryS* entry) { if (NULL == entry) { return ; } free(entry); } //创建一个LRU缓存 int LRUCacheCreate(int capacity, void **lruCache) { LRUCacheS* cache = NULL; if (NULL == (cache = malloc(sizeof(*cache)))) { perror("malloc"); return -1; } memset(cache, 0, sizeof(*cache)); cache->cacheCapacity = capacity; cache->hashMap = (cacheEntryS**)malloc(sizeof(cacheEntryS)*capacity); if (NULL == cache->hashMap) { free(cache); perror("malloc"); return -1; } memset(cache->hashMap, 0, sizeof(cacheEntryS)*capacity); *lruCache = cache; return 0; } //释放一个LRU缓存 int LRUCacheDestroy(void *lruCache) { LRUCacheS* cache = (LRUCacheS*)lruCache; if (NULL == cache) { return 0; } if (cache->hashMap) { free(cache->hashMap); } freeList(cache); free(cache); return 0; } /**************************************************** * 双向链表相关接口及实现 *****************************************************/ //从双向链表中删除指定节点 static void removeFromList(LRUCacheS *cache, cacheEntryS* entry) { //链表为空 if (cache->lruListSize == 0) { return; } if (entry == cache->lruListHead && entry == cache->lruListTail) { //当链表仅剩当前一个节点 cache->lruListTail = cache->lruListHead = 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(LRUCacheS *cache, cacheEntryS* entry) { cacheEntryS *removeEntry = NULL; if (++cache->lruListSize > cache->cacheCapacity) { /* 如果缓存满了,即链表当前节点数已等于缓存容量,那么需要先删除链表表尾节点,即淘汰最久没有被访问到的缓存数据单元*/ removeEntry = 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 removeEntry; } //释放整个链表 static void freeList(LRUCacheS *cache) { //链表为空 if (0 == cache->lruListSize) { return; } cacheEntryS* entry = cache->lruListHead; while(entry) { cacheEntryS *temp = entry->lruListNext; freeCacheEntry(entry); entry = temp; } cache->lruListSize = 0; } //辅助性接口,用于保证最近访问的节点总是位于链表表头 static void updateLRUList(LRUCacheS *cache, cacheEntryS *entry) { //摘抄节点 removeFromList(cache, entry); //将节点插入到链表表头 insertToListHead(cache, entry); } /**************************************************** * hash表相关接口及实现 *****************************************************/ //哈希函数 static int hashKey(LRUCacheS *cache, char key) { return (int)key%cache->cacheCapacity; } //从哈希表中获取缓存单元 static cacheEntryS *getValueFromHashMap(LRUCacheS *cache, char key) { //使用函数定位数据存放在哪个槽中 cacheEntryS *entry = cache->hashMap[hashKey(cache,key)]; //遍历槽内链表,找到准确的数据项 while(entry) { if (entry->key == key) { break; } entry = entry->hashListNext; } return entry; } //向hash表中插入缓存单元 static void insertentryToHashMap(LRUCacheS *cache, cacheEntryS *entry) { //使用函数定位数据存放在哪个槽中 cacheEntryS *n = cache->hashMap[hashKey(cache, entry->key)]; if (n != NULL) { //如果槽内已经有其他数据项,将巢内数据项与当前预加入数据项组成链表 //当前预加入数据项为表头 entry->hashListNext = n; n->hashListPrev = entry; } //将数据项放到到哈希槽内 cache->hashMap[hashKey(cache, entry->key)] = entry; } //从哈希表中删除缓存单元 static void removeEntryFromHashMap(LRUCacheS *cache, cacheEntryS *entry) { //无需做任何删除操作的情况 if (NULL == entry || NULL == cache || NULL == cache->hashMap) { return ; } //定位数据位于哪个槽内 cacheEntryS *n = cache->hashMap[hashKey(cache, entry->key)]; //遍历槽内链表,找到与删除节点,将节点从哈希表摘除 while(n) { //找到预删除节点,将节点从hash表摘除 if (n->key == entry->key) { if (n->hashListPrev) { n->hashListPrev->hashListNext = n->hashListNext; } else { cache->hashMap[hashKey(cache, entry->key)] = n->hashListNext; } if (n->hashListNext) { n->hashListNext->hashListPrev = n->hashListPrev; } } n = n->hashListNext; } } /**************************************************** * hash表相关接口及实现 *****************************************************/ //将数据放入LRU缓存中 int LRUCacheSet(void *lrucache, char key, char data) { LRUCacheS *cache = (LRUCacheS *)lrucache; //从hash表查找数据是否已经在缓存中 cacheEntryS* entry = getValueFromHashMap(cache, key); if (NULL != entry) { //更新数据,将数据项更新至链表表头 entry->data = data; updateLRUList(cache, entry); } else //数据没在缓存中,新建缓存插入链表表头 { entry = newCacheEntry(key, data); cacheEntryS *removeEntry = insertToListHead(cache, entry); if (NULL != removeEntry) { //缓存满,淘汰最近最久没有被访问到的数据单元 removeEntryFromHashMap(cache, removeEntry); freeCacheEntry(removeEntry); } insertentryToHashMap(cache, entry); } return 0; } char LRUCacheGet(void *lruCache, char key) { LRUCacheS *cache = (LRUCacheS *)lruCache; cacheEntryS *entry = getValueFromHashMap(cache, key); //检查hash缓存是否已经存在数据 if (NULL != entry) { //缓存中存在数据,更新至表头 updateLRUList(cache, entry); return entry->data; } else { return '