# [data structure] handwritten double linked list [pure C language version]

Abstract: this chapter mainly describes the implementation of circular double linked list

### Introduction to this chapter

In this chapter, I will not describe the implementation logic of the code in detail. If you have read the previous articles or written your own single linked list, you will grasp the implementation of circular double linked list in this article; If you are not clear about some of the logic, you can draw your own pictures to understand. Here I will only draw two pictures as a demonstration. Others can draw their own pictures. Drawing is really important!

### 1. Logical structure of circular double linked list

Here, I take the circular double linked list of the leading node as an example:

Each node has a data field and two pointer fields. Prev points to the previous element of the node and next points to the next node of the node. The connection between each two nodes is bidirectional, so we can find the direct precursor and direct successor of the node through any node; It is worth noting that the prev of the head node points to the tail node, and the next field of the tail node points to the head node, which forms a circular linked list.

### 2. Code implementation of circular double linked list

#### 2.1 define the storage structure of circular double linked list

```// Defines the type of linked list data field
typedef int LTDataType;

// Define linked list type
typedef struct ListNode
{
struct ListNode* prev; // Point to the previous node, that is, point to the direct precursor node
struct ListNode* next; // Point to the next node, that is, point to the direct successor node
LTDataType data; // Data domain
} ListNode;
```

#### 2.2 creating nodes

```// New node
{
if (!data)
{
printf("Data field cannot be empty\n");
return NULL;
}

// Create a new node
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
// Air judgment
if (!newNode)
{
perror("Failed to open up space");
return NULL;
}

// insert data
newNode->data = *data;
// next points to null
newNode->next = NULL;
// prev points to null
newNode->prev = NULL;

return newNode;

}
```

#### 2.2 initializing header nodes

When there is only one node in the circular double linked list, that is, the head node, the prev field and the next field of the head node point to themselves.

```void ListInit(ListNode** pphead)
{
int a = 10;
// Create a new node
ListNode* newNode = BuyListNode(&a);
// Point to yourself
newNode->next = newNode;
newNode->prev = newNode;
}
```

#### 2.3 calculate the length of the linked list

When calculating the length of the circular double linked list, we will keep the linked list variable. Then the problem comes. As long as the leading node circular double linked list is not empty, it will always have a direction. What should be our cycle termination condition? Very simple, when the current node is the head node, it means that the double linked list has been traversed.

```// Calculate the length of the double linked list, excluding the head node
{
// Record current node
ListNode* cur = phead->next;
// Record length
size_t size = 0;
// If the current node is not a header node
while ( cur != phead )
{
cur = cur->next;
size ++;
}
return size;
}
```

#### 2.4 tail interpolation

```void ListPushBack(ListNode* phead, LTDataType* data)
{

// Create a new node
ListNode* newNode = BuyListNode(data);
// Save tail node
ListNode* tail = phead->prev;
// The next of the tail node points to the new node
tail->next = newNode;
// The prev of the new node points to the tail node
newNode->prev = tail;
// The next of the new node points to the header node
// The prev of the head node points to the new node
// Complete insertion
}
```

#### 2.5 tail deletion method

```// Tail deletion
{
// If the linked list is empty, it will be interrupted

// Calculate linked list length
size_t size = ListSize(phead);
// If the size is less than 1, there are only header nodes in the linked list
if (size < 1)
{
printf("There are no nodes in the linked list\n");
exit(-1);
}

// Save tail node
ListNode* tail = phead->prev;
// Save the previous node of the tail node
ListNode* tailPrev = tail->prev;

free(tail);
tail = NULL;
}
```

#### 2.6 print linked list

```void ListPrint(ListNode* phead)
{

// Record current node
ListNode* cur = phead->next;
while ( cur != phead)
{
printf("%p\t%d\t%p\t%p\n", cur->prev, cur->data, cur->next, cur);
cur = cur->next;
}
}
```

#### 2.7 head insertion method

```// Head insert
void ListPushFront(ListNode* phead, LTDataType* data)
{
// Create a new node
ListNode* newNode = BuyListNode(data);

// Method 1: the sequence of the following codes in this method cannot be disordered, otherwise header insertion cannot be realized

// Method 2: the code order of this method can be changed

}
```

#### 2.8 header deletion

```// Header deletion
{
// Header node cannot be empty
// Calculate linked list length

// Method 1: the following code sequence can be disrupted
ListNode* target = phead->next;
ListNode* targetNext = target->next;
free(target);

// Method 2: the following code sequence cannot be disturbed
}
```

#### 2.9 finding nodes with specified data

```// Find the node with the specified data field and return the pointer of the node
ListNode* ListFind(ListNode* phead, LTDataType* data)
{

ListNode* cur = phead->next;

while (cur != phead)
{
if (cur->data == *data) return cur;
cur = cur->next;
}

return NULL;

}
```

#### 2.10 find nodes at specified locations

```// Find the node of the location. The value of pos is [0,size-1]
ListNode* ListFindByPos(ListNode* phead, size_t pos)
{
// Interrupt if there is only a header node
// Calculate the length of the current linked list
size_t size = ListSize(phead);
assert(pos < size);

// Used to record nodes with pos position
ListNode* posNode = phead->next;

for (int i = 0; i < pos; i++)
{
posNode = posNode->next;
}

return posNode;
}
```

#### 2.11 insert node before any node

```// Insert a new node before any node target
void ListInsert(ListNode* target, LTDataType* data)
{
assert(target);

ListNode* targetPrev = target->prev;
// Create a new node
ListNode* newNode = BuyListNode(data);

targetPrev->next = newNode;
newNode->prev = targetPrev;
newNode->next = target;
target->prev = newNode;
}
```

#### 2.12 find the specified node

```// Find whether there is a specified node in the linked list. The node is returned, but NULL is not returned
ListNode* ListIsExistNode(ListNode* phead, ListNode* target)
{

ListNode* cur = phead->next;
while (cur && (cur != phead))
{
if (cur == target) return cur;
cur = cur->next;
}
return NULL;
}
```

#### 2.13 delete specified node

```// Delete specified node
void ListErase(ListNode* target)
{
assert(target);

ListNode* targetPrev = target->prev;
ListNode* targetNext = target->next;

targetPrev->next = targetNext;
targetNext->prev = targetPrev;
free(target);
}
```

#### 2.14 empty linked list

```// Clear the linked list and keep the header node
{

ListNode* cur = phead->next;
while (cur != phead)
{
ListNode* next = cur->next;
free(cur);
cur = next;
}

}
```

#### 2.15 release linked list

```// Release the linked list, including the header node
{
// Empty linked list memory
// Set the linked list to empty
}
```

### 3. Source code link

Click to view the source code

[document description]

file nameexplain
SList.hType definition and function declaration of linked list
SList.cImplementation of specific functions
test.cTest code

### Postscript

My level is limited and mistakes are inevitable. I hope you can correct me.

This is the end of the double linked list. Thank you for reading!!! If the content is helpful to you, remember to give me sanlianya (praise, collection and attention)

All articles in my blog are original. Some articles or cite relevant materials, but the source has been clearly indicated. You can reprint and share at will, but you need to add a link to this article and a copyright description.

Posted on Sat, 06 Nov 2021 19:11:44 -0400 by Cleanselol