Data structure: linked list (linked-list)

Before discussing the linked list (linked-list), several concepts need to be clarified: linear list (sequential list, list, linear list), array (array), linked list (linked-list).

Linear table: In Chinese, linear table is also called sequence table. In English, it is called list, linear list, etc. It is the most basic, simplest, and most commonly used basic data structure. Each data stored in the linear table is called an element, and each element and its index are in a one-to-one correspondence. There are two storage methods for linear tables: sequential storage and chained storage.

Array: An array is a sequential storage method of a linear table . The memory of the array is allocated contiguously and statically, i.e. a fixed-size space needs to be allocated before using the array. The elements in the array can be directly obtained by indexing, that is, the time complexity of obtaining the elements in the array is O(1).

Linked-list: A linked list is a chained storage method of a linear list . The memory of the linked list is discontinuous, and the storage address of the previous element is not necessarily the next element. A linked list links the elements of the linked list with a reference to the address of the next element.

Arrays and Linked Lists 
Source: http://i.stack.imgur.com/puPVJ.jpg

In fact, for the sake of simplicity, usually we also directly regard the list as a linked list. But don't worry too much about this name definition, and more importantly, focus on the implementation of the data structure.

The thing and the name of the thing are two different things - Richard Feynman

Linked list classification

Linked list is divided into singly linked list (Singly linked list), doubly linked list (Doubly linked list), circular linked list (Circular Linked list).

Singly linked list

A singly linked list is the simplest form of a linked list. We call the most basic data in a linked list a node, and each node contains a block of data and a pointer to the next node.

Singly linked list 
Source: https://upload.wikimedia.org/wikipedia/commons/4/45/Link_en.png

typedef struct node
{
    int val;
    struct node *next;
}Node;
  • 1
  • 2
  • 3
  • 4
  • 5

head node

Singly linked lists are sometimes divided into headed nodes and headless nodes. A linked list with a head node is more convenient to implement (every time a new element is inserted, there is no need to judge whether the first node is empty), and the length of the linked list can be stored directly in the data block part of the head node, without using The entire linked list is traversed each time.

// create a new node with a value
Node* CreateNode(int val)
{
    Node *newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL) 
    {
        printf("out of memory!\n");
        return NULL;
    } else
    {
        newNode->val = val;
        newNode->next = NULL;
        return newNode;
    }
}

int main(){

    Node *head = CreateNode(0);

    //insert new value into list, end with END_INPUT(999)
    int value;
    while (scanf("%d", &value) && value != END_INPUT)
    {
        Insert(head, value);
    }

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

insert

There are two ways to insert a new element in a linked list: post-insertion and pre-insertion. Post-insertion is to insert a new element at the end of the linked list each time, and pre-insertion is to insert a new element at the head of the linked list.

The post-insertion method is more in line with the usual way of thinking and guarantees the sequence of inserting data. However, since only the head node is saved, each time a new element is inserted, it must be re-traversed to the end of the linked list. To solve this problem, consider adding a tail pointer to the last node of the linked list.

back plug 
Source: http://c.biancheng.net/cpp/uploads/allimg/140709/1-140F9153GJ93.jpg

void Insert(Node *head, Node *tail, int val)
{
    Node *newNode = CreateNode(val);
    tail->next = newNode;
    tail = tail->next;
    head->val ++;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Since the front insertion method is to insert a new element at the head, each time a new element is added, it can be directly indexed by the head pointer, but the resulting element order is opposite to the insertion order.

front insertion 
Source: http://c.biancheng.net/cpp/uploads/allimg/140709/1-140F9152T3201.jpg

void Insert(Node *head, int val)
{
    Node *newNode = CreateNode(val);
    newNode->next = head->next;
    head->next = newNode;
    head->val ++;
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

delete

Since the singly linked list only stores the head pointer, when deleting an element in the singly linked list, it is necessary to find the predecessor node of the target node.

delete node

void DeleteByVal(Node *head, int val)
{
    if (head->next == NULL)
    {
        printf("empty list!\n");
        return;
    }

    //find target node and its precursor
    Node *cur = head->next, *pre = head;
    while(cur)
    {
        if (cur->val == val)
            break;
        else {
            cur = cur->next;
            pre = pre->next;
        }
    }

    //delete target node
    pre->next = cur->next;
    free(cur);
    head->val--;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

Clear the linked list

Since the memory in the linked list is manually allocated, it needs to be deleted manually when it is no longer used.

void Free(Node *head)
{
    for (Node *temp = head; temp != NULL; temp = head->next) 
    {
        head = head->next;
        free(temp);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

linked list reversal


Node* Reverse (Node* head) {

    if (head == NULL || head->next == NULL)
        return head;
    else {

        Node *cur = head->next,
             *pre = NULL,
             *next = NULL;

        while (cur != NULL) {

            next = cur->next;
            cur->next = pre;
            pre = cur;
            cur = next;
        }

        head->next = pre;

        return head;
    }        
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

Doubly linked list

As the name suggests, a doubly linked list is a linked list with two directions. Unlike a singly linked list, each node in a doubly linked list not only stores a pointer to the next node, but also stores a pointer to the previous node. In this way, the predecessor node can be found directly through the destination node in O(1) time, but at the same time, a large amount of pointer storage space will be increased.

Doubly linked list

typedef struct node
{
    int val;
    struct node *pre;
    struct node *next;
}Node;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

insert

The operation of inserting a new element in a doubly linked list is similar to the operation of inserting a new element in a singly linked list.

write picture description here

Node* CreateNode(int val)
{
    Node *newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL) 
    {
        printf("out of memory!\n");
        return NULL;
    } else
    {
        newNode->val = val;
        newNode->next = NULL;
        newNode->pre = NULL;
        return newNode;
    }
}

void Insert(Node *head, int val)
{
    Node *newNode = CreateNode(val);
    newNode->next = head->next;
    head->next->pre = newNode;
    head->next = newNode;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

delete

Since each node in the doubly linked list records its predecessor node, it does not need to index the predecessor node of the destination node as in the singly linked list, but can be obtained directly through the target node.

write picture description here

Node* FindByVal(Node *head, int val)
{
    for(Node* temp = head; temp != NULL; temp = temp->next)
    {
        if (temp->val == val)
            return temp;
    }
    return NULL;
}


void DeleteByVal(Node *head, int val)
{
    Node *target = FindByVal(val);
    if (target == NULL)
    {
        printf("not find target value!\n");
        return;
    }

    target->pre->next = target->next;
    target->next->pre = target->pre;
    free(target);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

other

  • How to judge whether the current node is the first node?
  • How to judge whether the current node is the last node? 
    In a doubly linked list, the predecessor node of the first node is not the head node, but points to a null pointer. Likewise, the back driver of the last node points to a null pointer.

Circular Linked list

A circular linked list is similar to a doubly linked list, the difference is that a pointer to the head node is added at the end of the linked list, the head node also adds a pointer to the tail node, and the first node points to the head node. Convenient for indexing linked list elements.

doubly linked list 
Source: http://p.blog.csdn.net/images/p_blog_csdn_net/blacklord/%E5%9B%BE2.15.JPG

insert, delete

The insertion and deletion operations of a circular linked list are implemented in the same way as a doubly linked list.

Determine empty linked list, linked list head and tail

It can be clearly observed from the above figure (a) that there is only one head node in an empty doubly circular linked list, and both the predecessor and the successor of the head node point to itself.

As can be seen from Figure (b), different from the doubly linked list, the first node and the tail node in the circular linked list do not point to a null pointer, but point to the head node.

Reprinted from: https://blog.csdn.net/juanqinyang/article/details/51351619

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325598363&siteId=291194637