Bidirectional circular linked list of leading nodes (C language)

Keywords: C Visual Studio

Concept: bidirectional linked list is that each node has a precursor pointer in addition to the subsequent pointer. and Single linked list Similarly, the two-way linked list also has the structure of the leading node and the structure of the non leading node. The two-way linked list of the leading node is more commonly used; In addition, the two-way linked list can also have circular and non circular structures. The two-way linked list with circular structure is more commonly used.

Next, we will implement a most commonly used two-way circular linked list of leading nodes. Similar to the following figure:

1. Initialization:

First, the structure of each node must be given with the help of the structure:

typedef int DataType;
typedef struct ListNode{
	struct ListNode *prev;//Precursor pointer
	DataType val;//Numerical domain
	struct ListNode *next;//Successor pointer
}ListNode;

  All nodes of the following code linked list are stored on the heap, so first give a pointer of ListNode type and assign it null, and then make this pointer point to the head node of the linked list applied on the heap through initialization. The specific code is as follows:

ListNode *pplist = NULL;
pplist = ListCreate();
ListNode* ListCreate(){//Create header node
	ListNode *pos = BuyListNode(0);//Call the function of creating a node to get the address of the newly applied node
	pos->prev = pos;//The precursor pointer points to itself
	pos->next = pos;//The subsequent pointer points to itself
	return pos;//Returns the address of the header node
}
ListNode* BuyListNode(DataType x){//Create a node
	ListNode *pos = (ListNode *)malloc(sizeof(ListNode));//Request a node on the heap
	if (pos == NULL){//Judge whether the application is successful
		perror("malloc");//Output error message
		exit(0);//Exit program
	}
	pos->prev = NULL;//Assign a null value to the precursor pointer of the newly applied node
	pos->val = x;//Assign a value to the node value field of the new application
	pos->next = NULL;//Assign a null value to the subsequent pointer of the newly applied node
	return pos;//Returns the address of the newly applied node
}

When creating a header node, it can be rewritten to pass in a secondary pointer (according to your own preferences), but when applying for a separate node, it is generally written according to the above method with return value, because it is uncertain which pointer points to the newly applied node. It should also be noted that the data field of the head node can not be given a value (in this code, I give 0), and the two pointer fields of the head node point to itself, as shown in the following figure:

2. After initialization, you can add, delete, modify and query the bidirectional circular linked list.

Header insertion: header insertion is to connect the newly applied node to the header node. Be careful not to disconnect the original linked list in a hurry. After assigning a value to the pointer field of the newly applied node, disconnect the original linked list to prevent the loss of the original data. The specific operation code is as follows:

void ListPushFront(ListNode* plist, DataType x){//Head insert
	assert(plist);
	ListNode *pos = BuyListNode(x);//Get the address of the newly applied node first
	pos->prev = plist;//Let the precursor pointer of the newly applied node point to the head node
	pos->next = plist->next;//Make the subsequent pointer of the newly applied head node point to the next node of the head node in the original linked list
	plist->next->prev = pos;//The precursor pointer of the next node of the head node in the original linked list points to the newly applied node
	plist->next = pos;//The subsequent pointer of the header node points to the newly applied node
}

In the previous blog (single linked list without leading node), header insertion needs to pass the secondary pointer. Why not pass the secondary pointer here? Because the direction of the head pointer will not change and will always point to the head node (unless the linked list is destroyed), you can find the precursor pointer and successor pointer of the head node of the linked list by passing the first level pointer. At this time, you only need to modify the direction of these two pointers.

In the following figure, there is a node behind the head node in the original linked list by default. After calling the function, a temporary variable plist is formed, which points to the head node like pplist. At this time, you only need to find the head node through plist.

Header deletion:   For the first node after deleting the head node, note that the location of this node should be recorded first to free up space. The specific code is as follows:

void ListPopFront(ListNode* plist){//Header deletion
	assert(plist);
	if (plist->prev == plist){
		printf("No element\n");
		return;
	}
	ListNode* cur = plist->next;//Record the position of the node after the header node
	plist->next = cur->next;//The subsequent pointer of the head node points to the second node after the head node in the original linked list
	cur->next->prev = plist;//Let the leading pointer of the second node after the head node point to the head node
	free(cur);//Free up space
}

The code logic of tail deletion and tail insertion is similar to the above code and will not be repeated.

Search: start from the first node after the first node, and traverse the whole linked list. Exit condition: cur==plist.

ListNode* ListFind(ListNode* plist, DataType x){//lookup
	assert(plist);
	ListNode *cur = plist->next;//Find from the first node
	while (cur!=plist){//Traverse the whole linked list
		if (cur->val==x){
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

After writing these, there are two functions that can be implemented, that is, inserting and deleting nodes at any position before any position. After writing these two functions, you will find that header insertion, tail insertion, header deletion and tail deletion can be implemented by these two functions at one time. In fact, only two functions can be implemented for the deletion and insertion of bidirectional circular linked list, The complete code and test results are as follows (using multiple files):

1.ListNode.h

#include <stdio.h>
#include <windows.h>
#include <assert.h>
typedef int DataType;
typedef struct ListNode{
	struct ListNode *prev;//Precursor pointer
	DataType val;//Numerical domain
	struct ListNode *next;//Successor pointer
}ListNode;
extern ListNode* ListCreate();
extern ListNode* BuyListNode(DataType x);
extern void ListPushFront(ListNode* plist, DataType x);
extern void ListPopFront(ListNode* plist);
extern void ListPushBack(ListNode* plist, DataType x);
extern void ListPopBack(ListNode* plist);
extern void ListDestory(ListNode** plist);
extern void ListInsert(ListNode* pos, DataType x);
extern void ListErase(ListNode* pos);
extern void ListPrint(ListNode* plist);
extern ListNode* ListFind(ListNode* plist, DataType x);

2.ListNode.c

#include "ListNode.h"
ListNode* ListCreate(){//Create header node
	ListNode *pos = BuyListNode(0);//Call the function of creating a node to get the address of the newly applied node
	pos->prev = pos;//The precursor pointer points to itself
	pos->next = pos;//The subsequent pointer points to itself
	return pos;//Returns the address of the header node
}
ListNode* BuyListNode(DataType x){//Create a node
	ListNode *pos = (ListNode *)malloc(sizeof(ListNode));//Request a node on the heap
	if (pos == NULL){//Judge whether the application is successful
		perror("malloc");//Output error message
		exit(0);//Exit program
	}
	pos->prev = NULL;//Assign a null value to the precursor pointer of the newly applied node
	pos->val = x;//Assign a value to the node value field of the new application
	pos->next = NULL;//Assign a null value to the subsequent pointer of the newly applied node
	return pos;//Returns the address of the newly applied node
}
void ListPushFront(ListNode* plist, DataType x){//Head insert
	assert(plist);
	/*ListNode *pos = BuyListNode(x);//Get the address of the newly applied node first
	pos->prev = plist;//Let the precursor pointer of the newly applied node point to the head node
	pos->next = plist->next;//Make the subsequent pointer of the newly applied head node point to the next node of the head node in the original linked list
	plist->next->prev = pos;//The precursor pointer of the next node of the head node in the original linked list points to the newly applied node
	plist->next = pos;*///The subsequent pointer of the header node points to the newly applied node
	ListInsert(plist->next, x);
}
void ListPopFront(ListNode* plist){//Header deletion
	assert(plist);
	if (plist->prev == plist){
		printf("No element\n");
		return;
	}
	/*ListNode* cur = plist->next;//Record the position of the node after the header node
	plist->next = cur->next;//The subsequent pointer of the head node points to the second node after the head node in the original linked list
	cur->next->prev = plist;//Let the leading pointer of the second node after the head node point to the head node
	free(cur);*///Free up space
	ListErase(plist->next);
}
void ListPopBack(ListNode* plist){//Tail deletion
	assert(plist);
	if (plist->prev == plist){
		printf("No element");
		return;
	}
	/*ListNode *cur = plist->prev;
	cur->prev->next = plist;
	plist = cur->prev;
	free(cur);*/
	ListErase(plist->prev);
}
void ListPushBack(ListNode* plist, DataType x){//Tail insertion
	assert(plist);
	/*ListNode *pos = BuyListNode(x);
	pos->prev = plist->prev;
	pos->next = plist;
	plist->prev->next = pos;
	plist->prev = pos;*/
	ListInsert(plist, x);
}
ListNode* ListFind(ListNode* plist, DataType x){//lookup
	assert(plist);
	ListNode *cur = plist->next;//Find from the first node
	while (cur!=plist){//Traverse the whole linked list
		if (cur->val==x){
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}
void ListInsert(ListNode* pos, DataType x){//Insert before any position
	assert(pos);
	ListNode *cur = BuyListNode(x);
	cur->prev=pos->prev;
	cur->next =pos ;
	pos->prev->next = cur;
	pos -> prev = cur;
}
void ListErase(ListNode* pos){//Delete anywhere
	assert(pos);
	if (pos->prev == pos){
		printf("No element\n");
		return;
	}
	pos->prev->next = pos->next;
	pos->next->prev = pos->prev;
	free(pos);
}
void ListPrint(ListNode* plist){//Print
	assert(plist);
	if (plist->prev == plist){
		printf("No element\n");
		return;
	}
	ListNode *cur = plist->next;
	while (cur!=plist){
		printf("->%d", cur->val);
		cur = cur->next;
	}
	printf("\n");
}
void ListDestory(ListNode** plist){//Destroy
	assert(plist);
	assert(*plist);
	ListNode *cur = (*plist)->next;
	while (cur!=*plist){
		(*plist)->next = cur->next;
		free(cur);
		cur = (*plist)->next;
	}
	free(*plist);
	*plist = NULL;
}

3.main.c

#include "ListNode.h"
int main(){
	ListNode *pplist = NULL;
	pplist = ListCreate();
	ListPushFront(pplist, 6);
	ListPushBack(pplist, 9);
	ListPushFront(pplist, 7);
	ListPushBack(pplist, 8);
	ListPrint(pplist);
	ListPopFront(pplist);
	ListPopBack(pplist);
	ListPrint(pplist);
	ListInsert(ListFind(pplist, 6),96);
	ListPrint(pplist);
	ListErase(ListFind(pplist, 96));
	ListPrint(pplist);
	system("pause");
	return 0;
}

 

Posted by Pethlehemm on Mon, 29 Nov 2021 03:06:36 -0800