用hash map和双向链表实现LruCache

       之前介绍过hash table, 也介绍过hash map,  当然, 双向链表也早就说过, 现在来看看如何用这些东西来实现一个LruCache,  直接上代码:

#include <iostream>
#include <vector>
#include <ext/hash_map>     // for hashmap
using namespace std;
using namespace __gnu_cxx;  // for hashmap
 
template <class K, class V>
struct Node
{
    K key;
    V data;
    Node *pPrev;
	Node *pNext;
};

template <class K, class V>
class LRUCache
{
private:
    hash_map<K, Node<K,V>* > m_hashmap;           // O(1)查找,记录key是否存在

    Node<K,V> *m_pHead;
	Node<K,V> *m_pTail;
	
    Node<K,V> *m_pEntry;
	vector<Node<K,V>* > m_vecPEntry;              // 管理可用结点
	
public:
    LRUCache(size_t size)
	{
        m_pEntry = new Node<K,V>[size];
        for(size_t i = 0; i < size; i++)
        {
			m_vecPEntry.push_back(m_pEntry + i);  // 初始化可用结点
		}

		// 双向链表初始化, 引入头结点和尾结点是为了操作统一化
        m_pHead = new Node<K,V>;
        m_pTail = new Node<K,V>;
        m_pHead->pPrev = NULL;
        m_pHead->pNext = m_pTail;
        m_pTail->pPrev = m_pHead;
        m_pTail->pNext = NULL;
    }
	
    ~LRUCache()
	{
		if(NULL != m_pHead)
		{
			delete m_pHead;
			m_pHead = NULL;
		}

		if(NULL != m_pTail)
		{
			delete m_pTail;
			m_pTail = NULL;
		}
   
	   if(NULL != m_pEntry)
	   {
		   delete [] m_pEntry;    // []不可漏
		   m_pEntry = NULL;
	   }
    }

    void Put(K key, V data)
	{
        Node<K,V> *pNode = m_hashmap[key];
        if(NULL != pNode)         // 该key之前已经存在,则更新值,并调整到双向链表的表头
		{
            detach(pNode);
            pNode->data = data;
            attach(pNode);
			return;
        }

        if(m_vecPEntry.empty())   // 无可用结点,则双向链表最后的结点需要滚蛋
		{
            pNode = m_pTail->pPrev;
            detach(pNode);
            m_hashmap.erase(pNode->key);
        }
        else                      // 有可用结点,则取可用结点
		{
            pNode = m_vecPEntry.back();
            m_vecPEntry.pop_back();
        }

		// 塞到双向链表的表头
        pNode->key = key;
        pNode->data = data;
        attach(pNode); 

		m_hashmap[key] = pNode;
    }
	
    V Get(K key)
	{
        Node<K,V> *pNode = m_hashmap[key];
        if(NULL != pNode)         // key已经存在,该次访问后,需放在链表的头部
		{
            detach(pNode);
            attach(pNode);
            return pNode->data;
        }
        else                      // key不存在
		{
            return V();
        }
    }
	
private:
   void detach(Node<K,V>* pNode)  // 从双向链表中删除当前结点(不要delete了,后面还会用)
   {
        pNode->pPrev->pNext = pNode->pNext;
        pNode->pNext->pPrev = pNode->pPrev;
   }

   void attach(Node<K,V>* pNode)  // 将当前结点插入双向链表头部
   {
        pNode->pPrev = m_pHead;
        pNode->pNext = m_pHead->pNext;
        m_pHead->pNext = pNode;
        pNode->pNext->pPrev = pNode;
    }
};


int main()
{
    LRUCache<int, string> lru_cache(1000);
	
    lru_cache.Put(1, "hello");
    cout << lru_cache.Get(1) << endl;
	
    if(lru_cache.Get(2).empty())
    {
    	cout << "no key" << endl;
	}
	
	lru_cache.Put(2, "world");
    cout << lru_cache.Get(2) << endl;
	
    return 0;
}

        结果:

hello
no key
world

       要好好体会一下。

       不多说。

猜你喜欢

转载自blog.csdn.net/stpeace/article/details/81275613
今日推荐