# 1, Lead two-way circular linked list

We realized it earlier Headless one-way acyclic linked list , features: simple structure, generally not used to store data separately. In fact, it is more used as a substructure of other data structures, such as hash bucket, adjacency table of graph and so on. In addition, this structure appears a lot in OJ questions, so we need to simulate the implementation and fully understand its characteristics.

The headless one-way acyclic linked list has disadvantages, that is, the last node must be found when tail inserting and tail deleting. The time complexity is O(N), and it is inconvenient to consider whether it is deleted for the head node.
In view of these shortcomings, we will implement the lead two-way circular linked list. The structure of the lead two-way circular linked list is complex. It is generally used to store data separately. The structure is a little complex, but the implementation is very simple.

# 2, Take the lead in the realization of two-way circular linked list

Similar to the previous implementation of headless one-way acyclic linked list, we also need to create a node data type, which is the data field and pointer field, but the pointer field needs to store the address of the previous node and the address of the next node.

```typedef int DataTypedef; //Rename the int type DataType

struct ListNode
{
DataTypedef data;        //Data domain
struct ListNode* next;   //Pointer field, which stores the address of the next node
struct ListNode* prev;   //Pointer field, which stores the address of the previous node
};

//Rename the linked list type struct ListNode LNode
typedef struct ListNode LNode;
```

Then, after having the type, we can create a linked list type pointer plist, which is used to maintain the head node (sentinel bit) of the leading two-way circular linked list.
Then use the pointer plist to maintain the sentinel node opened on the heap, but pay attention to one thing:
To transfer the address of pointer plist, the content of pointer plist cannot be transferred;
Because if you want to change the content stored by the pointer plist, you need to pass the address of the pointer plist, and then use the secondary pointer to receive the address of the plist, so as to dereference the content stored by the pointer plist, so as to change the sentinel node maintained by the pointer plist.

# 4, Initialization of two-way circular linked list

Initialization needs to open up a sentinel node to prepare for the later interface, and the sentinel node stores the addresses of the previous node and the next node. This design can reduce a lot of trouble. We will analyze later. We will implement initialization first. The code is as follows:

```//Initialization function
{
LNode* tmp = (LNode*)malloc(sizeof(LNode));
if (tmp == NULL)
{
perror("erron ");
exit(-1);
}

tmp->next = tmp;
tmp->prev = tmp;
tmp->data = 0;
}
```

# 5, Implementation of two-way circular linked list interface:

## 1. Insert data in the tail

The code implementation is as follows:

```//Open up new node function
{
LNode* newNode = (LNode*)malloc(sizeof(LNode));
if (newNode == NULL)
{
perror("erron ");
exit(-1);
}
newNode->data = x;
return newNode;
}

//Tail insertion
void ListPushBack(LNode* phead,DataTypedef x)
{
LNode* newNode = BuyNewNode(x); //Open up a node

//Find the last node. The front of the sentry position is the tail node
LNode* tail = phead->prev;

// tail   newNode  phead;
//Link a new node after the last node
tail->next = newNode;
newNode->prev = tail;
}
```

If we have implemented a headless one-way acyclic linked list, we will consider many situations in this process. For example, we will ask why we do not consider the case that the linked list is empty and there is only one sentry position? Can such a special situation be realized?

This shows the advantage of storing the next and previous nodes of the sentry bit as their own addresses during initialization. This design can be realized even if the chain is empty. You can draw and analyze the structural design, which is very ingenious. As long as there are sentinels, you don't have to consider whether the linked list is empty. This is also a supplement to the disadvantages of headless one-way acyclic linked list.

## 2. Insert data into the header

```//Head insert
void ListPushFront(LNode* phead, DataTypedef x)
{
LNode* newNode = BuyNewNode(x);
//Find the first node first
LNode* next = phead->next;

//Insert between the sentinel node and the first node
newNode->next = next;
next->prev = newNode;
}

```

## 3. Delete data at the end

The code implementation is as follows:

```//Tail deletion
{
//To ensure that there are nodes in the linked list that can be deleted, the sentry position cannot be deleted
LNode* tail = phead->prev;
//To find the previous of the tail node
LNode* tailPrev = tail->prev;

//Connect the previous one of the tail node with the sentinel position

//Finally, release the tail node
free(tail);
}

```

## 4. Delete header data

The code implementation is as follows:

```//Header deletion
{
//To ensure that there are nodes in the linked list that can be deleted, the sentry position cannot be deleted

//Find the second node
LNode* start = phead->next->next;
//Release U-turn node

//Just connect the sentry position with the second node
}
```

## 5. Display data

Display the data and print out the data field in the node. The code is as follows:

```//Display data
{
//Traverse from the next node of the sentry position
LNode* cur = phead->next;

//Equal to the sentinel position is to return to the starting point and stop traversal
while (cur != phead)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
```

## 6. Find data

Find the information in the data field. If they are equal, return the address of the change node. The code is as follows:

```//Find data
LNode* ListFind(LNode* phead, DataTypedef x)
{
//Start from the next node of the sentry position
LNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
```

## 7. Insert data in front of the node

The code is as follows:

```//Insert before node
void ListInsert(LNode* pos, DataTypedef x)
{
assert(pos);
//Find the node in front of pos position
LNode* posPrev = pos->prev;
LNode* newNode = BuyNewNode(x);

//posPrev  newNode  pos
//Just insert between them
posPrev->next = newNode;
newNode->prev = posPrev;
newNode->next = pos;
pos->prev = newNode;

}
```

## 8. Delete current location data

The implementation code is as follows:

```//Delete current node data
void ListErase(LNode* pos)
{
assert(pos);
//Find the node before and after the pos position
LNode* posPrev = pos->prev;
LNode* posNext = pos->next;

// posPrev   posNext
//Just connect them
posPrev->next = posNext;
posNext->prev = posPrev;
}
```

## 9. Memory release

```//Memory release
{
//Release from the next node of the sentry position
LNode* cur = (*pphead)->next;
while (cur != *pphead)
{
LNode* next = cur->next;
free(cur);
cur = next;
}
//Finally, release the sentry post
}
```

# 6, Modification of the plug with head and tail

You can find that our insertion and deletion functions are very similar to the head and tail plug deletion, so we don't need to write a head and tail plug deletion again; We can call the insert and delete functions directly.
The transformation is as follows:

```//Tail insertion
void ListPushBack(LNode* phead,DataTypedef x)
{

//Inserting in front of the sentinel node is the tail insertion
//Just call the insert function
}

void ListPushFront(LNode* phead, DataTypedef x)
{

//The insertion in front of the next node of the sentinel node is the head insertion
//Direct call to insert function
}

//Tail deletion
{
//To ensure that there are nodes in the linked list that can be deleted, the sentry position cannot be deleted

//Delete the front position of the sentinel position node is the tail deletion
//Direct call to delete function
}

{
//To ensure that there are nodes in the linked list that can be deleted, the sentry position cannot be deleted

//The next node to delete the sentry position is header deletion
//Direct call to delete function