Linked list summary-common linked lists, how to implement the LRU cache elimination algorithm, and how to write the code of the linked list

Contrast with array

basic introduction

When it comes to the storage of data structures, we can easily think of the two most basic storage methods, arrays and linked lists. After learning related content, we can easily think of the advantages and disadvantages of the two:
Array :
suitable for data Search, but delete and insert data is very time-consuming. When applying for internal space, the specific size must be determined. Once declared, the entire continuous memory space will be occupied. If the declared array is too large, the system may not have enough contiguous memory space allocated to it, resulting in "insufficient memory". Of course, the vector array in C++ solves this problem, and the corresponding Arraylist in Java also solves this problem, but it exceeds it. Capacity, what is their handling mechanism? They will apply for a larger space, and then copy all the original data in. We know that copying data is also a very time-consuming task, so this still has a disadvantage.
Linked list :
Suitable for data insertion and deletion, but it is more difficult to find data, and it takes a long time to traverse. The linked list itself has no size limit and naturally supports dynamic expansion. I think this is also the biggest difference between it and an array. It does not store data like an array and does not need a continuous space. It connects different spaces through pointers.
Insert picture description here

analysis

For random access to the array again, as long as we know the serial number, we can directly access it, but if we want to insert, assuming that the inserted serial number is k, then we need to move all the elements after k back by one. If it is the last number, We can insert the data directly into the last position. At this time, the time complexity is O(1). If it is the first number, the time complexity is O(n). ComprehensiveThe average time complexity is O(n)If it is deleted, it will all move one bit to the front, and the average time complexity is O(n);
if the linked list is randomly accessed, it must be traversed from the first number to the back one by one until we find the value we need to find, assuming Is the first number, then the time complexity is O(1), if it is the last number, the time complexity is O(n),The average time complexity is O(n)

Several common linked lists

First of all, first show several common linked lists below:

  1. Single list
  2. Circular linked list
  3. Doubly linked list
  4. Double circular linked list

Single list

Insert picture description here
A singly linked list is the most basic linked list, so it must be mastered. The linked list connects a group of scattered memory blocks together through pointers. Among them, we call the memory block the "node" of the linked list. In order to string up all the nodes, in addition to storing data, each node of the linked list also needs to record the address of the next node on the chain. As shown in the figure, we call this pointer that records the address of the next node as the successor pointer next.

Circular linked list

Insert picture description here
On the basis of the singly linked list of the circular linked list, the last pointer to NULL is reset to point to the head node to realize a circular mechanism.

Doubly linked list

Insert picture description here
The doubly linked list is based on the singly linked list, adding a prev pointer to point to the previous node.

Double circular linked list

Insert picture description here
The doubly circular linked list is the combination of doubly linked list and circular linked list. This is also the most used. Here is a method of replacing space with time. It adds memory, but in some cases it runs faster than singly linked lists. Quickly, let's say delete a piece of data. Some common algorithm books will say that the time complexity of a single necklace table is O(1), but is this really the case? Let's take a closer look.
Usually there are two situations for a new data in mind:

  1. Delete the node with "value equal to a given value" in the node;
  2. Delete the node pointed to by the given pointer.

For case 1, we use a singly linked list. We must first traverse to find the node we need to delete. Therefore, in this sense, its time complexity is actually O(n), of course at this time The same is true for doubly circular linked lists, there is no difference.
But for case 2, it is different. If you want to delete a node at a given position, you must find its previous node, so we must traverse first, and delete it until p->next==q. The time complexity here is O(n), and the doubly circular linked list (doubly linked list) can find the previous node directly by q->prev and delete it, which is O(1) here.

How to implement the LRU cache elimination algorithm

LRU cache elimination algorithm

First of all, before writing this, we must first know,What is LRU cache elimination algorithm.
Caching is a technology to improve the performance of data reading. It is widely used in hardware design and software development, such as common CPU cache, database cache, browser cache, and so on. The size of the cache is limited. When the cache is full, which data should be cleared out and which data should be kept? This requires a cache elimination strategy to decide.
There are three common strategies: FIFO (First In, First Out), LFU (Least Frequently Used),LRU (Least Recently Used).
Suppose you have bought a lot of technical books, but one day you find that these books are too many and take up too much study space. You have to clean up and throw away some books. At this time, which books would you choose to throw away? Correspondingly, are your selection criteria similar to the above three strategies?

How to implement the LRU cache elimination algorithm

We maintain an ordered singly linked list. The nodes closer to the end of the linked list are accessed earlier. When a new data is accessed, we traverse the linked list sequentially starting from the head of the linked list.
When a piece of data comes in, we need a variable to see if it appears in the linked list.

  1. Appear: take this data to the head of the linked list
  2. Nothing appears:
    a. If the cache is not full at this time, insert this node directly into the head of the linked list;
    b. If the cache is full at this time, the end node of the linked list is deleted, and the new data node is inserted into the linked list. head.

In this way, we have implemented the LRU cache elimination algorithm with a linked list.

How to write linked list code

1. Pay attention to the meaning of pointers

Since the linked list contains a lot of pointers, it is naturally very difficult to write the code of the linked list if the meaning of the pointers is not understood. Therefore, we must know the meaning of the pointers, so how should the pointers be understood?
Assigning a variable to a pointer is actually assigning the address of the variable to the pointer, or vice versa, the memory address of the variable is stored in the pointer, and the variable can be found through the pointer.
Here are specific examples:

p->next=q表示p的next指针存储了q的内存地址
p->next=p->next->next表示p 结点的 next 指针存储了 p 结点的下下一个结点的内存地址。

2. Beware of pointer loss and memory leaks

How to say it, roughly when we write code again, often due to some errors, a linked list becomes half or some fragments are out of control and can no longer be mobilized by pointers, such as the following:Insert picture description here

//插入一个结点(将q插到p的下一个)
p->next=q;
q->next=p->next;

We can easily find that this code is a mistake, because p->next is already q, but q->next is still q. This is obviously wrong, because the original p->next has been out of our linked list, so we need How to correct it? We only need to change the order of the two codes and it is OK. Therefore, when we insert a node , we must pay attention to the order of operations . We must determine the next node of the new node and point to the new node.
In the same way, when deleting a linked list node, you must also remember to manually release the memory space, otherwise, memory leaks will also occur.

3. Add a header node to simplify the code

During our normal operation, if we need to insert a new node, then the operation we need is:

q->next=p->next;
p->next=q;

However, if this is an empty linked list, it does not meet the above code, we should do this:

if (p==NULL)
	node* p = new node;

In the same way, if we want to delete the node of the linked list, the code we need is:

p->next=p->next->next;

However, if you want to delete the last position of the linked list, does this operation cause problems again? We should write:

if(p->next==NULL)
	p=NULL;

Therefore, do you think there is some trouble, how to solve this problem?
Insert picture description here
Just add a head node: the head node is a node that does not contain data, and it is added just to unify the code and facilitate writing.

4. Pay attention to the handling of boundary conditions

When writing the code of the linked list, pay more attention to whether the code is satisfied within the boundary range, such as:

  1. Is it satisfied when the list is empty
  2. Does the code work normally when the linked list contains only one node?
  3. Does the code work normally when the linked list contains only two nodes?
  4. Does the code logic work normally when processing the head node and the end node?

If there is no problem, then there is basically no problem;

5. You can draw images to help understand and write codes

For example, the picture I drew above is to link the linked list. If there is a picture, writing code may become more convenient and less error-prone.
Insert picture description here

6. Write more and practice more

If you are not the kind of person with a particularly high IQ, it is recommended to write more exercises on the linked list. If you practice more, you can write naturally and smoothly. Here are a few exercise questions. If you are interested, you can write about it.

  1. Singly linked list inversion
  2. Detection of rings in linked lists
  3. Two ordered linked lists merge
  4. Delete the nth node from the bottom of the linked list
  5. Find the middle node of the linked list

In another blog of mine, I wrote 1, 3, and 4 of them. If necessary, you can refer to that blog, and attach its link below:
Link: Basic operation of C++ linked list-the structure of linked list , The destruction of the linked list, the insertion of the linked list, the deletion of the linked list, the inversion of the linked list, the inversion of the head interpolation

At this point, the blog is over. If it is helpful to you, you may wish to give it a thumbs up.

Guess you like

Origin blog.csdn.net/Freedom_cao/article/details/107408721