Implementing an LRU Cache using C + +

Source: Internet
Author: User

What is the LRU Cache

LRU is the abbreviation for least recently used, which means the least recently used. It is a cache replacement algorithm.

What is the cache? The narrow cache refers to high-speed RAM, which is located between the CPU and main memory, and typically does not use DRAM technology like system main memory, but uses expensive but high-speed SRAM technology.

The broad-sense cache refers to a structure that is located between two hardware with a large speed difference, which is used to coordinate the transmission of data speed differences.

In addition to the cache between the CPU and main memory, there is also a cache between the RAM and the hard disk, and even between the hard disk and the network there is a sense of cache── called the Internet temporary directory or network content cache.

Cache capacity is limited, so when the cache capacity is exhausted, and new content needs to be added, it is necessary to select and discard the original part of the content, so as to make room to put new content. The LRU cache replacement principle is to replace the least recently used content.

In fact, LRU translates into 最久未使用 more image, because each time the algorithm is replaced is the longest period of time has not been used content.

Data

The typical implementation of LRU is hash map + doubly linked list . A doubly linked list is used to store data nodes. And it is stored according to the time that the node was recently used.

Given that a node has been interviewed, we have reason to believe that it will be more likely to be interviewed in the next few days than other nodes. So, we put it on the head of the doubly linked list. When we insert a node into the two-way link table. We also have the possibility to use it very quickly, the same as inserting it into the head. We use such a way to constantly adjust the two-way list, linked to the end of the list is also a recent period of time, the longest unused nodes. Then, when our cache is full, the one that needs to be replaced is the last node in the doubly linked list (not the tail node, and the tail-end node does not store the actual content).

For example, the following is a doubly linked list. Note that the Kinsoku node does not store the actual content:

头 --> 结 --> 结 --> 结 --> 尾结       点        点       点       结点 <-- 1  <-- 2 <-- 3  <-- 点

If the cache is full. We're going to replace the node 3.

What is the function of a hash table? Assuming there is no hash table, we have to visit a node. they need to be searched sequentially. The complexity of Time is O (n).

Using a hash table allows us to find the node that we want to visit at O (1) time. or return not found.

Cache interface

The cache has two main interfaces:

TGet(Kkey);voidPut(Kkey,Tdata);

When we access data of type T by key value, we call the Get function.

Assume that the data with key value key is already in the cache. That data is returned, and the node that stores the data is moved to the doubly linked list header at the same time. Assuming that the data we are querying is not in the cache, we are able to insert the data into the doubly linked list via the put interface. Suppose the cache is not full at this time. Then we insert the new node into the list header, and at the same time we use a hash table to store the node's key value and the node address pair.

Assuming the cache is full, we replace the contents of the last node in the list (note not the tail node) with the new content. Then move to the head and update the hash table.

C + + code

Note that hash map is not part of the C + + standard, I use Linux under g++ 4.6.1,hash_map under/usr/include/c++/4.6/ext, need to use the __gnu_cxx name space. The Linux platform is able to switch to the Include folder for C + +: cd/usr/include/c++/version number and then Grep-ir "Hash_map"./view in which file, the last lines of the general header file indicate the name space in which it resides. Explore other platforms on your own.

Xd

Of course, if you're already using C + + 11 very fashion, you won't have these little problems.

A simple LRU cache written in c++//Hash map + doubly linked list#include <iostream> #include <vector> #inclu De <ext/hash_map>using namespace std;using namespace __gnu_cxx;template <class K, class t>struct node{k ke    Y    T data; Node *prev, *next;}; Template <class K, class T>class Lrucache{public:lrucache (size_t size) {Entries_ = new Node<k,t>[si        Ze];        for (int i=0; i<size; ++i)//Store the address of the available nodes Free_entries_.push_back (entries_+i);        Head_ = new node<k,t>;        Tail_ = new node<k,t>;        Head_->prev = NULL;        Head_->next = Tail_;        Tail_->prev = Head_;    Tail_->next = NULL;        } ~lrucache () {delete head_;        Delete Tail_;    Delete[] Entries_;        } void Put (K key, T data) {node<k,t> *node = Hashmap_[key];            if (node) {//node exists detach (node);            Node->data = data;        Attach (node); } else{if (Free_entries_.empty ()) {//Available nodes are empty, that is, cache is full node = tail_->prev;                Detach (node);            Hashmap_.erase (Node->key);                } else{node = Free_entries_.back ();            Free_entries_.pop_back ();            } Node->key = key;            Node->data = data;            Hashmap_[key] = node;        Attach (node);        }} T Get (K key) {node<k,t> *node = Hashmap_[key];            if (node) {Detach (node);            Attach (node);        Return node->data; } else{//assume that there is no cache. Returns the default value of T.        Consistent with HashMap behavior return T ();        }}private://Detach node void Detach (node<k,t>* node) {Node->prev->next = node->next;    Node->next->prev = node->prev;        }//Insert node into head void Attach (node<k,t>* node) {node->prev = Head_;        Node->next = head_->next; Head_->next = node;       Node->next->prev = node;    }private:hash_map<k, node<k,t>* > Hashmap_; vector<node<k,t>* > Free_entries_;    Stores the address of the available nodes node<k,t> *head_, *tail_; Node<k,t> *entries_;    Nodes in a doubly linked list};int main () {hash_map<int, int> map;    map[9]= 999;    cout<<map[9]<<endl;    cout<<map[10]<<endl;    Lrucache<int, string> lru_cache (100); Lru_cache.    Put (1, "one"); Cout<<lru_cache.    Get (1) <<endl; if (Lru_cache. Get (2) = = "") Lru_cache.    Put (2, "both"); Cout<<lru_cache.    Get (2); return 0;}

Analytical:
The list is used first to manage all the nodes that are already in use or in use (that is, physical memory pages). Just beginning to allocate some nodes, stored in the vector, before the buffer is not used to be stored in the vector. When the vector
Buffer is used, it must be taken from the last one in the list to be used as a new node.

When finding the position of a node in a linked list, it is very inefficient to assume that each time it is looked up from scratch.
Hash_map to manage all the nodes in the list, hash_map are used nodes, which is very convenient to find.

Implementing an LRU Cache using C + +

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.