LRUCache design, implementation and commissioning

The design concept + realization of ideas comb over comb over 1 + 1 times combing debugging method

Preliminaries

In late March 2020 [2] algorithm discussion list # 17

The main question to answer

  1. Design
    1.1 Data structure of how selection.
    1.2 Data structure of each field is how come.

  2. achieve

  3. Debugging method

Two kinds of questions

One is leetcode topic, you realize directly put, get
one is to design and implement their own LRUCache. The first question is part of the second question.

  • LRU said a phase-out strategy.
    The limited size of the cache, when the cache is filled with, what data should be cleared out, what data should be retained?
    This requires the elimination of caching strategies to decide. There are three common strategies: FIFO strategy FIFO (First In, First Out) , the least used tactics LFU (Least Frequently Used), the least recently used strategy LRU (Least Recently Used).

Design (discussion carding)

Clear demand

  • The main function of
    storage cache, full time and need out of some cache, eliminating the policy is LRU.

  • Design The first step: Scenario Testing (scenario testing) / use test
    simulation process using a LRU's clear what we want to achieve something. // This step is an important step to do a lot of software design, such as interface design and framework API design.
    If the capacity of the cache is 2.
    put1-1, put2-2, put3-3 (out. 1)
    put1-1, put2-2, get1-1 / put1-11, put3-3 (out 2)

  • Whereby the two comb design elements of the data structure
    1, is a put, get a set of operation. In fact, there delete operation removes the specified key (such as put1-11, we can either move the old node to the head node, you can also delete the old node and create a new node is inserted into the head).
    2, this collection needs to have some sort of order so that we can determine to be phased out in the elements out of here is to be phased out at the end of the element, out of direct elimination can be.
    3, out of cache and cache least recently used strategy to enhance the strategy is to use recently.

Choose what data structure

1. Why did you choose list

As can be seen from the test scene, doing put / get operations, there are a lot of head inserted into the collection, a collection of deletion tail. Our structure is nothing more than storage arrays, linked lists, trees,
arrays insert head O (n) Delete O (n), insert head the list of O (1) Delete O (n) + O (1 ), the tree does not seem to end to end node a say, and we generally were chosen from easy to difficult, the list seems to be here to meet the needs.
The list is divided into single-linked lists, doubly-linked lists, circular single chain, double loop chain, jump table.
This produces the first edition design: first choose a single linked list.

2. Why is the introduction of map

The first list is O (n) to find another O (1) Delete. Can be optimized by introducing a map look-up table O (1) Delete.
At this time, generating a second version of the design: map {cache key-> single linked list node pointer list} + {val, next}.

3. Why did you choose a doubly linked list

The second version of the design using a delete operation, we need to know the pre removed node node, so it is necessary to save pre node somewhere.

  1. Stored in the map, then the map is {key (key cache, pre Node) ->} node pointers, list node design {val, next} // This requires a new structure, and it is the key structure is very strange , discarding the program.
  2. Save the node list: map cache design {key->} node pointers, list node design {pre, val, next}, this is a doubly linked list.

This produces third edition design: map {cache key->} + double linked list node pointer list {pre, val, next}

4. Why map has been saved key, list node also needs to be saved key

Consider a situation: When the cache is full, we need to remove the nodes in a linked list, also need to be removed in the map corresponding to the key. Probably steps are as follows:

1. 定位到尾节点,删除链表尾节点。
因为需要"定位到尾节点", 所以该数据结构需要引入1个tail来记录尾节点的地址。
第1步O(1)。
2. 定位尾节点在map中的键值对并删除该键值对。
"定位尾节点对应的键值", 因为链表节点没有保存key, 所以我们哪不到key, 也就不能直接delete(map,key), 而是需要遍历map来查找尾节点(v==tail的节点)然后删除。
第2步是O(n)。
So at this time of the delete operation is designed to O (n) because of the need to traverse map, we can store the key to eliminating this list node traversal. Direct can be directly deleted by delete (map, tail.key), without having to traverse the map. Steps 1 and 2 so that it is O (1) is.

This produces Fourth Edition Design: [tail + map {cache key-> node pointer list}] + double linked list {pre, key, val, next}.

The introduction of the head and tail Why

Before we consider deleting nodes in the case, now head to consider the case interpolation insert the head node.
Clearly we need a head pointer to quickly locate the head node.

This produces fifth edition Design: [head + tail + map {cache key-> node pointer list}] + double linked list {pre, key, val, next}.

6. Why head, tail needs to be dummy node

We know that the introduction of a single list of deleted dummyhead is to unify the head node and the intermediate node deletion logic. Dummyhead introduced here is the same reason.
As to why the introduction of dummytail, consider [head <-> 1 <- > 2] and [head <-> 1 <- > nil], you can see if there is no tail, then, when you remove the tail nodes have head <- nil abnormality is deleted and the intermediate node is tail node deleting two sets of logic, it is also introduced to unify dummytail intermediate node to delete the logical [head <-> tail].

At this time, produce a sixth version of the design: [dummyhead + dummytail + map {cache key-> node pointer list}] + 双向循环链表{pre, Key, Val, Next}.

6.5 Another benefit of two-way circular list

Two-way circular linked list is initialized to [head <-> tail], then no matter what we insertions and deletions to the list, the entire list is nil node does not exist, so we do not worry about air access nodes caused by the abnormal situation.

7. increase the cache size field

This produces Seventh Edition Design: [dummyhead + dummytail + map {cache key-> node pointer list} + cap] + doubly linked list {pre, key, val, next}.

Intuition implementation code

很多点没考虑到,写不走,上述7个版本的设计都是事后归因来总结的。

Code implementation (together first to write about)

We should focus on how we are to extract such a common basis for the operation remove and add.
In further an idea which further extracted common operations such moveToHead.

  • put
  • get

debugging

Critical information to debug by printing, higher than the debug efficiency.
Print writing code.

shorthand

  1. leetcode brush Title: 3:00
    1.1 map + bidirectional circular list. Initialization [head <-> tail]
    1.2 PUT, GET, Remove, the Add, the operation is split into two four operations
    1.3 put operation According to exist, full discussion in 4 cases, and in some cases to see consolidation.

  2. Interview: The handwriting a little time-consuming, generally do not test, said the main design ideas, version 7 should not have so many, but we need to answer: // This I doubt, need to be discussed.
    Why introduction map, the array is not selected from the group selected from the list, a doubly linked list is selected, and the dummy node bidirectional circular linked list.
    2 Why node fields are added to it, what their function is?

reference

06 | list (on): How to implement LRU cache replacement algorithms?

Guess you like

Origin www.cnblogs.com/yudidi/p/12622296.html