• 【算法33】LRU算法


    题目来源

    LeetCode: https://leetcode.com/problems/lru-cache/

    LRU简介

    LRU (Least Recently Used,最近最少使用)算法是操作系统中一种经典的页面置换算法,当发生缺页中断时,需要将内存的一个或几个页面换出,LRU指出应该将内存最近最少使用的那些页面进行换出,依据的是程序的局部性原理,最近经常使用的页面在不久的将来也很有可能被使用,反之最近很少使用的页面未来也不太可能再使用。

    LRU 数据结构

    LRU采用双向链表+hash表的数据结构实现,双向链表作为队列存储当前缓存节点,其中从表头到表尾的元素按照最近使用的时间进行排列,放在表头的是最近刚刚被使用过的元素,表尾的最近最少使用的元素;如果仅仅采用双向链表,那么查询某个元素需要 O(n) 的时间,为了加快双向链表中元素的查询速度,采用hash表讲key进行映射,可以在O(1)的时间内找到需要节点。

    LRU主要实现以下两个接口:

    int Get(int key);
    void Put(int key, int value);

    其中 Get 用来读取队列中的元素,同时需要将该元素移动到表头;Put 用来向队列中插入元素。

    LRU 具体实现

    从实现的角度来看,每次 Get 时, 需要判断该 key 是否在队列中,如果不在,返回-1;如果在,需要重新移动该元素到表头位置(具体实现,可以先删除,在插入到表头)。 每次 Put 时,首先需要判断key是否在队列中,如果在,那么更新其 value值,然后移动该元素到表头即可;如果不在,需要进一步判断,队列是否已满,如果已满;那么需要首先删除队尾元素,并对 size - 1, 删除哈希表中对应元素的 key;然后在插入新的元素到队头。

    具体C++代码如下:

      1 /**
      2  * LRU Cache Implementation using DoubleLinkList & hashtable
      3  * Copyright 2015 python27
      4  * 2015/06/26
      5  */
      6 #include <iostream>
      7 #include <string>
      8 #include <map>
      9 #include <list>
     10 #include <deque>
     11 #include <cassert>
     12 #include <cstdio>
     13 #include <cstdlib>
     14 using namespace std;
     15 
     16 struct CacheNode
     17 {
     18     int key;
     19     int value;
     20     CacheNode* prev;
     21     CacheNode* next;
     22     
     23     CacheNode(int k, int v) : key(k), value(v), prev(NULL), next(NULL)
     24     {}
     25     
     26     CacheNode():key(0), value(0), prev(NULL), next(NULL)
     27     {}        
     28 };
     29 
     30 class LRUCache
     31 {
     32 public:
     33     LRUCache(int capacity);
     34     
     35     int Get(int key);
     36     void Put(int key, int value);
     37     
     38 public:
     39     void PrintList() const;
     40 private:
     41     void InsertNodeFront(CacheNode* p);
     42     void DeleteNode(CacheNode* p);
     43     
     44 private:
     45     map<int, CacheNode*> m_hashtable;        // hash table
     46     CacheNode* m_head;                        // double link list head
     47     CacheNode* m_tail;                        // double link list tail
     48     int m_capacity;                            // capacity of link list
     49     int m_size;                                // current size of link list
     50 };
     51 
     52 void LRUCache::PrintList() const
     53 {
     54     CacheNode* p = m_head;
     55     for (p = m_head; p != NULL; p = p->next)
     56     {
     57         printf("(%d, %d)->", p->key, p->value);
     58     }
     59     printf("
    ");
     60     printf("size = %d
    ", m_size);
     61     printf("capacity = %d
    ", m_capacity);
     62 }
     63 
     64 LRUCache::LRUCache(int capacity)
     65 {
     66     m_capacity = capacity;
     67     m_size = 0;
     68     m_head = NULL;
     69     m_tail = NULL;
     70 }
     71 
     72 //    insert node into head pointed by p
     73 void LRUCache::InsertNodeFront(CacheNode* p)
     74 {
     75     if (p == NULL) return;
     76     
     77     if (m_head == NULL)
     78     {
     79         m_head = p;
     80         m_tail = p;
     81     }
     82     else
     83     {        
     84         p->next = m_head;
     85         m_head->prev = p;
     86         m_head = p;
     87     }
     88 }
     89 
     90 // delete node in double linklist pointed by p
     91 void LRUCache::DeleteNode(CacheNode* p)
     92 {
     93     if (p == NULL) return;
     94     
     95     assert(m_head != NULL && m_tail != NULL);
     96     
     97     if (m_size == 1)
     98     {
     99         if (p == m_head && p == m_tail)
    100         {
    101             delete p;
    102             m_head = NULL;
    103             m_tail = NULL;
    104         }
    105         else
    106         {
    107             fprintf(stderr, "Delete Wrong! No such Node");
    108             return;
    109         }
    110     }
    111     else if (p == m_head)
    112     {
    113         m_head = m_head->next;
    114         m_head->prev = NULL;
    115         delete p;
    116     }
    117     else if (p == m_tail)
    118     {
    119         m_tail = m_tail->prev;
    120         m_tail->next = NULL;
    121         delete p;
    122     }
    123     else
    124     {
    125         p->prev->next = p->next;
    126         p->next->prev = p->prev;
    127         delete p;
    128     }
    129     
    130 }
    131 
    132 int LRUCache::Get(int key)
    133 {
    134     // if key not in return -1
    135     if (m_hashtable.find(key) == m_hashtable.end())
    136     {
    137         return -1;
    138     }
    139         
    140     CacheNode* p = m_hashtable[key];
    141     int k = p->key;
    142     int v = p->value;
    143     
    144     // delete this node
    145     DeleteNode(p);
    146         
    147     // insert this node to the head
    148     p = new CacheNode(k, v);
    149     InsertNodeFront(p);
    150     // update hash table
    151     m_hashtable[k] = p;
    152     return p->value;
    153 }
    154 
    155 void LRUCache::Put(int key, int value)
    156 {
    157     // if key alread in, update
    158     if (m_hashtable.find(key) != m_hashtable.end())
    159     {
    160         CacheNode* p = m_hashtable[key];
    161         
    162         // delete node
    163         DeleteNode(p);
    164         // insert node
    165         p = new CacheNode(key, value);
    166         InsertNodeFront(p);
    167         // update hash table
    168         m_hashtable[key] = p;
    169         return;
    170     }
    171     // if list is full, delete the tail node
    172     else if (m_size >= m_capacity)
    173     {
    174         // delete the tail node
    175         CacheNode* p = m_tail;
    176         m_hashtable.erase(p->key);
    177         DeleteNode(p);
    178         m_size--;
    179     }
    180     
    181     // create node and insert into head
    182     assert(m_size < m_capacity);
    183     CacheNode* p = new CacheNode(key, value);
    184     InsertNodeFront(p);
    185     m_hashtable[key] = p;
    186     m_size++;
    187 }
    188 
    189 int main()
    190 {
    191     LRUCache lru(3);
    192     lru.Put(1, 11);
    193     lru.PrintList();
    194     lru.Put(2, 22);
    195     lru.PrintList();
    196     lru.Put(3, 33);
    197     lru.PrintList();
    198     lru.Put(4, 44);
    199     lru.PrintList();
    200     int value = lru.Get(3);
    201     printf("Get(3) = %d
    ", value);
    202     lru.PrintList();
    203     value = lru.Get(2);
    204     printf("Get(2) = %d
    ", value);
    205     lru.PrintList();
    206     value = lru.Get(4);
    207     printf("Get(4) = %d
    ", value);
    208     lru.PrintList();
    209     value = lru.Get(1);
    210     printf("Get(1) = %d
    ", value);
    211     lru.PrintList();
    212     
    213     return 0;
    214 }
  • 相关阅读:
    Windows Azure Cloud Service (14) 使用Windows Azure诊断收集日志记录数据
    Windows Azure Cloud Service (13) 用Visual Studio 2010 将应用程序部署到Windows Azure平台
    Windows Azure Cloud Service (15) 多个VM Instance场景下如何处理ASP.NET Session
    Windows Azure Storage (5) Windows Azure Drive
    Windows Azure Storage (7) 使用工具管理Windows Azure Storage
    SQL Azure(二) SQL Azure vs SQL Server
    webbrowser的自动提交
    提取视频的背景声音的软件
    Listview列排序的bug原因
    两个奇怪的问题
  • 原文地址:https://www.cnblogs.com/python27/p/LRUCache.html
Copyright © 2020-2023  润新知