The chain storage structure of linear list two way linked list and two way circular linked list

Time:2021-6-15

In the last article, we introducedSingle linked list and circular linked listNow let’s look at two-way linked lists and two-way circular linked lists.

1. Two way linked list

In a single linked list, each node has a pointer to its direct successor node, and the whole single linked list can only operate in one direction. As the name suggests, a bidirectional linked list contains not only the address pointer of the direct successor node, but also the address pointer of its direct precursor node.
Node definition:

#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OK 1

typedef int Status;/*  Status is the type of function, and its value is the function result status code, such as OK*/
typedef int ElemType;/*  The type of ElemType depends on the actual situation. Here, it is assumed to be int*/

//Define node
typedef struct Node{
    ElemType data;
    struct Node *prior;
    struct Node *next;
}Node;

typedef struct Node * LinkList;

The node structure is as follows:
The chain storage structure of linear list two way linked list and two way circular linked list
After understanding the node structure, let’s take a look at the structure diagram of the non empty linked list
Leading node:
The chain storage structure of linear list two way linked list and two way circular linked list
No leading node:
The chain storage structure of linear list two way linked list and two way circular linked list

1.1 creation of bidirectional linked list

For the creation of bidirectional linked list, we create the linked list of the leading node by default.
Thinking:

  1. Open up space, create the head node, and judge whether the creation is successful.
  2. Set the leader pointer to null and the successor pointer to null.
  3. Create nodes in turn through the loop, and add to the end of the list.
  4. Return to success.

The code implementation is as follows:

//Create two way linked list
Status createLinkList(LinkList *L){
    //*L points to the head node
    *L = (LinkList)malloc(sizeof(Node));
    if (*L == NULL) return ERROR;
    (*L)->prior = NULL;
    (*L)->next = NULL;
    (*L)->data = -1;
    
    //New data
    LinkList p = *L;
    for(int i=0; i < 10;i++){
        //1. Create a temporary node and set the initial value.
        LinkList temp = (LinkList)malloc(sizeof(Node));
        temp->prior = NULL;
        temp->next = NULL;
        temp->data = i;
        
        //2. Establish a bidirectional linked list relationship for the new node
        //Temp is the successor of P
        p->next = temp;
        //The precursor of temp is p
        temp->prior = p;
        //P to record the location of the last node for the next insertion
        p = p->next;
    }
    return OK;
}

1.2 two way linked list insertion node

Thinking:

  1. Create a new node temp and initialize it.
  2. Traverse to find the position of the precursor node of the insertion position node.
  3. If the inserted position is greater than the total length of the linked list, error is returned.
  4. Judge whether it is inserted in the tail. If it is, just modify the relationship between the tail node and the insertion node.
  5. If it is not inserted at the tail, the relationship between the inserted node and its predecessor node and successor node should be modified.
  6. Return to OK.

The chain storage structure of linear list two way linked list and two way circular linked list
The code implementation is as follows:

//Double linked list insertion node
Status ListInsert(LinkList *L, int i, ElemType data){
    //1. The insertion position is illegal, which is 0 or negative
    if(i < 1) return ERROR;
    
    //2. New node
    LinkList temp = (LinkList)malloc(sizeof(Node));
    temp->data = data;
    temp->prior = NULL;
    temp->next = NULL;
    
    //3. Point P to the head node!
    LinkList p = *L;
    
    //4. Find the node directly inserted in position i
    for(int j = 1; j < i && p;j++) 
        p = p->next;
    
    //5. If the inserted position exceeds the length of the linked list itself
    if(p == NULL){
        return  ERROR;
    }
    
    //6. Judge whether the insertion position is at the end of the linked list;
    if (p->next == NULL) {
        p->next = temp;
        temp->prior = p;
    }else
    {
        //1 set the precursor of P - > next node prior = temp
        p->next->prior = temp;
        //2. Point temp - > next to the original p - > next
        temp->next = p->next;
        //3 P > next update to the newly created temp
        p->next = temp;
        //4 newly created temp precursor = P
        temp->prior = p;
    }
    return  OK;
}

1.3 bidirectional linked list to delete the specified node

Thinking:

  1. Traverse to find the location of the precursor node of the deleted location node, and create a node pointer P pointing to the precursor node..
  2. If the inserted position is less than 1 or greater than the total length of the linked list, error is returned.
  3. The node pointer deltemp is created to point to the node to be deleted, and the next of node P is modified to point to the next of deltemp.
  4. If the node deltemp to be deleted has a successor node, modify the prior of its successor node to point to P.
  5. Release the deltemp node.
  6. Return to OK.

The chain storage structure of linear list two way linked list and two way circular linked list
The code implementation is as follows:

//Delete the node in the specified position of bidirectional linked list
Status ListDelete(LinkList *L, int i, ElemType *e){
    int k = 1;
    LinkList p = (*L);
    //1. Judge whether the two-way linked list is empty, and return error if it is empty;
    if (*L == NULL) {
        return ERROR;
    }
    //2. Move pointer p to the node before deleting element.
    while (k < i && p != NULL) {
        p = p->next;
        k++;
    }
    //If k > I or P = = null, error will be returned
    if (k>i || p == NULL) {
        return  ERROR;
    }
    //4. Create a temporary pointer deltemp to point to the node to be deleted, assign the data of the node to * e, and bring it back to the main function
    LinkList delTemp = p->next;
    *e = delTemp->data;
    //5. P - > next is the next node of the node to be deleted
    p->next = delTemp->next;
    //6. If the next node of the deleted node is not empty, the precursor pointer of the next node to be deleted is assigned P;
    if (delTemp->next != NULL) {
        delTemp->next->prior = p;
    }
    //7. Delete deltemp node
    free(delTemp);
    return OK;
}

1.4 bidirectional linked list to delete specified elements

Thinking:

  1. Create a node pointer P and point to the head node.
  2. Traverse the two-way linked list to find the node P which is equal to the specified value, that is, the node p to be deleted.
  3. If the node p to be deleted exists, modify the successor pointer of the predecessor node of node P. if P has a successor node, modify the predecessor pointer of the successor node of node P.
  4. Return to OK.

The code implementation is as follows:

//Delete the element specified by the bidirectional linked list
Status LinkListDeletVAL(LinkList *L, int data){
    //1. Judge whether the two-way linked list is empty, and return error if it is empty;
    if (*L == NULL) {
        return ERROR;
    }
    LinkList p = *L;
    //2. Traverse bidirectional linked list
    while (p) {
        //2. Judge whether the data field and data of the current node are equal, if so, delete the node
        if (p->data == data) {
            
            //Modify the successor pointer of the predecessor node of the deleted node
            p->prior->next = p->next;
            //Modify the precursor pointer of the successor node of the deleted node
            if(p->next != NULL){
                p->next->prior = p->prior;
            }
            //Release deleted node p
            free(p);
            //Exit loop
            break;
        }
        //If the node is not found, continue to move the pointer P
        p = p->next;
    }
    return OK;
}

1.5 two way linked list to find element location

Thinking:

  1. Create the node pointer P, point to the first element node, create the index I, and set it to 1
  2. Traverse the bidirectional list to find the node P corresponding to the specified index.
  3. If found, index I is returned.
  4. If not, return – 1.

The code implementation is as follows:

//Finding element position in bidirectional linked list
int selectElem(LinkList L,ElemType elem){
    LinkList p = L->next;
    int i = 1;
    while (p) {
        if (p->data == elem) {
            return i;
        }
        i++;
        p = p->next;
    }
    return  -1;
}

1.6 update node data with bidirectional linked list

Thinking:

  1. Create a node pointer P and point to the first element node.
  2. Traverse the bidirectional linked list to find the node p to be updated.
  3. Re assign p – > next.
  4. Return to OK.

The code implementation is as follows:

Status replaceLinkList(LinkList *L,int index,ElemType newElem){
    if (index < 1) {
        return ERROR;
    }
    LinkList p = (*L)->next;
    for (int i = 1; i < index && p->next != NULL; i++) {
        p = p->next;
    }
    p->data = newElem;
    return OK;
}

2. Two way circular linked list

As the name suggests, the bidirectional circular list is to connect the tail node and the head node of the bidirectional list, as shown in the following figure:
Empty two way circular list:
The chain storage structure of linear list two way linked list and two way circular linked list
Non empty bidirectional circular linked list:
The chain storage structure of linear list two way linked list and two way circular linked list

2.1 creation of bidirectional circular linked list

Thinking:

  1. Open up space, create the head node, and judge whether the creation is successful.
  2. The front pointer of the head node is set as the head node, and the subsequent pointer is set as the head node to form a closed loop.
  3. Create nodes in turn through the loop, and add to the end of the list.
  4. Return to success.

The code implementation is as follows:

//Initialization of bidirectional circular linked list
Status creatLinkList(LinkList *L){
    *L = (LinkList)malloc(sizeof(Node));
    if (*L == NULL) {
        return ERROR;
    }
    (*L)->next = (*L);
    (*L)->prior = (*L);
    //New data
    LinkList p = *L;
    for(int i=0; i < 10;i++){
        //1. Create a temporary node
        LinkList temp = (LinkList)malloc(sizeof(Node));
        temp->data = i;
        //2. Establish a bidirectional linked list relationship for the new node
        //Temp is the successor of P
        p->next = temp;
        //The precursor of temp is p
        temp->prior = p;
        //Temp is followed by * L
        temp->next = (*L);
        //The precursor of (* l) is the new temp
        (*L)->prior = temp;
        //P to record the location of the last node for the next insertion
        p = p->next;
    }
    return OK;
}

2.2 two way circular list insertion node

Thinking:

  1. Create a node pointer P and point to the head node.
  2. Traverse to find the node P before the insertion position.
  3. Create a new node temp and assign a value to it.
  4. Modify the context of the temp node.
    ① . set the precursor node of node temp to P.
    ② . set the successor node of node temp to p – > next.
    ③ . set the successor node of node p to temp.
    ④ . set the precursor node of the successor node of the node temp as temp.
  5. Return to OK.

The chain storage structure of linear list two way linked list and two way circular linked list

The code implementation is as follows:

//Insert element into bidirectional circular linked list
/*When the insertion position exceeds the length of the linked list, it is inserted at the end of the linked list*/
Status LinkListInsert(LinkList *L, int index, ElemType e){
    //1. If I > index, error is returned
    if (index < 1)  return ERROR;
    //2. Create a pointer p to the two-way Chain header
    LinkList p = (*L);
    int i = 1;
    //3. If the bidirectional circular linked list is empty, error will be returned
    if(*L == NULL) return ERROR;
    //4. Find the node P in the previous position
    while (i < index && p->next != *L) {
        p = p->next;
        i++;
    }
    //5. Create a new node temp
    LinkList temp = (LinkList)malloc(sizeof(Node));
    //6. If the temp node is empty, error is returned
    if (temp == NULL) return ERROR;
    //7. Assign the generated new node temp data field to E
    temp->data = e;
    //8. Set the precursor node of node temp as P;
    temp->prior = p;
    //9. The successor node of temp points to p - > next;
    temp->next = p->next;
    //The successor node of 10. P is the new node temp;
    p->next = temp;
    //11. The precursor of the next node of the temp node is the temp node
    temp->next->prior = temp;
    return OK;
}

2.3 bidirectional circular list deletion node

Thinking:

  1. Judge whether the linked list exists. If it does not exist, return.
  2. If only the first element node is left after deletion, then * l will be left blank.
  3. Create a node pointer, point to the first element node, traverse to find the deleted node temp, and assign the value of deleted node to * e.
  4. Modify the linked list connection relationship.
    ① . modify the successor pointer of the predecessor node of the deleted node temp.
    ② . modify the precursor pointer of the successor node of the deleted node temp.
  5. Release the deleted node temp.
  6. Return to OK.

The chain storage structure of linear list two way linked list and two way circular linked list

The code implementation is as follows:

//Bidirectional circular list deleting node
Status LinkListDelete(LinkList *L,int index,ElemType *e){
    int i = 1;
    LinkList temp = (*L)->next;
    if (*L == NULL) {
        return  ERROR;
    }
    //If only the first element node is left after deletion, then * l will be set to null directly;
    if(temp->next == *L){
        free(*L);
        (*L) = NULL;
        return OK;
    }
    //1. Find the node to delete
    while (i < index) {
        temp = temp->next;
        i++;
    }
    //2. Assign e the data field of the node to be deleted
    *e = temp->data;
    //3. Modify the successor pointer of the predecessor node of the deleted node
    temp->prior->next = temp->next;
    //4. Modify the precursor pointer of the successor node of the deleted node
    temp->next->prior = temp->prior;
    //5. Delete the node temp
    free(temp);
    return OK;
}

2.4 bidirectional circular list traversal

Thinking:

  1. Judge whether the linked list is empty. If it is empty, return directly.
  2. Create the node pointer temp and point to the first element node.
  3. Loop traverses temp. If temp is not the head node, output the value of temp node. If temp is the head node, the linked list has been traversed to the end and exits the loop.

The code implementation is as follows:

//Traversing bidirectional circular linked list
Status Display(LinkList L){
    if (L == NULL) {
        Printf ("the printed two-way circular list is empty\ n\n");
        return ERROR;
    }
    Printf ("two way circular linked list content");
    LinkList p = L->next;
    while (p != L) {
        printf("%d  ",p->data);
        p = p->next;
    }
    printf("\n\n");
    return OK;
}