Linked list (top)
@ (data structure and algorithm)
A classic application scenario for a linked list: LRU cache culling algorithm.
Caching is a count of improving data read performance, such as common: CPU caching, database caching, browser caching, and so on.
The size of the cache is limited, and when the cache is full, those data should be cleaned up, and the data should be retained, which requires a cache-out strategy algorithm to determine. There are three common strategies: FIFO (first in, firstly out), minimum usage policy LFU (Least frequently used), and least recently used policy LRU (Least recently used).
Structure of the linked list
From the underlying storage data structure, the array needs contiguous memory space to store, the memory requirements are relatively high, and the list does not need a contiguous memory space, it through the "pointer" of a set of scattered memory blocks in series to use.
A single linked list of two nodes is special, they are the first node and the last node, which is habitually referred to as the head node and tail nodes, the head node is used to record the base address of the linked list, and the tail nodes special place is: The pointer does not refer to the next node, but point to an empty address null.
Inserting or deleting a data in a linked list does not need to move nodes as arrays do to preserve memory continuity, so the time complexity of inserting and deleting operations in a linked list is $O (1) $.
But the advantage has the disadvantage, the link list drug randomly accesses the K element wrath, does not have the array to be so efficient, because the data in the list is not the continuous storage, therefore cannot like the array, according to the first address and the subscript, through the addressing formula can calculate directly the corresponding memory address, but needs according to the pointer one by one node's traversal Until the corresponding node is found. The time complexity is $o (n) $.
The circular list is a special single-linked list, with the only difference being that the node pointer points to the head node of the linked list.
Doubly linked list, each node has more than one successor pointer next points to the back node, and a precursor pointer prev points to the previous node, which obviously requires more memory.
In the actual delete operation, there are no exceptions in either case
- Delete a node in a node where "value equals a given value"
- Deletes the node pointed to by the given pointer
For the first case, whether a single-linked list or a doubly-linked list, it is necessary to traverse through the entire list from the beginning, until a node with a value equal to the given value is found and deleted, although the time complexity of the deletion is $O (1) $, but the time complexity of the lookup is $O (n) $, so the total time complexity is $O
For the second case, we have found the node to be deleted, but deleting a node Q needs to know its predecessor, and the single-linked list does not support direct acquisition of the precursor node, so it is still necessary to traverse from the head node until P->next = q is found, the time complexity is $O (n) $, For the doubly linked list, the Dzeko is deleted directly, with a time complexity of $O (1) $.
Similarly, if we want to insert a node insert operation before a specified node in the list, the doubly linked list can be done within $O (1) $ time complexity, while a single-linked list needs to $O (n) $ time complexity.
The important idea of the doubly linked list is the space change time, when the memory space is sufficient, if more pursuit of code execution speed, you can choose a relatively high spatial complexity, but relatively low time complexity of the algorithm or data structure, contrary to the same. And the cache is using the space to change the design idea of time.
List and Array comparisons
However, the comparison of arrays and linked lists is not limited to the complexity of time, and in the actual software development, it is not possible to use the complexity analysis to decide which data structure is used to store the data.
The array is easy to use, the continuous memory space used in the implementation can be read with the help of CPU's caching mechanism, so the access efficiency is higher. The list is not continuously stored in memory, so read-ahead is not supported.
Array declarations require a pre-allocated memory size, and the list naturally supports dynamic scaling. In addition, if the code for the use of memory is very harsh, the array is more suitable, because each node in the list needs to consume additional storage space, and the frequent incorporation of the linked list, delete operations, but also cause frequent memory requests and releases, prone to memory memory fragmentation.
The algorithm of LRU cache elimination based on linked list
Maintaining an ordered single-linked list, the closer the node to the end of the list, the earlier the access, when a new data is accessed, we traverse the linked list from the beginning of the chain.
- If this data has been previously cached in the linked list, it iterates over the node that corresponds to the data, removes it from its original location, and then inserts it into the list's head.
- If this data is not in the cache linked list, both cases
- When the cache is not full, the node is inserted directly into the list's head.
- When the cache is full, the end of the list node is deleted, and the new data node is inserted into the list header.
Reference from: Geek Time "the beauty of data structures and Algorithms" column
Linked list (top)