❤ C language -- linked list -- data structure ❤

Posted by rajsekar2u on Thu, 07 Oct 2021 20:27:00 +0200

1. Concept of linked list

Linked list is a basic data structure. Linked list can dynamically allocate storage. In other words, linked list is a very powerful array. It can define a variety of data types in nodes, and can add, delete and insert nodes as needed. We only allocate memory for one node at a time. The linked list uses pointers to combine various nodes together, thus forming a chain structure connected one by one. This is the origin of the name of the linked list.
The following describes how to add, delete and insert nodes in the linked list.

2. Implementation of linked list

2.1 structure of linked list

First, let's take a look at the specific structure of the linked list. It is linked by nodes one by one. Each node includes two parts, one is the data field to store the data content we want, and the other is the pointer field to connect the next node. The pointer field of the last node points to null. As shown in the figure below.

2.2 initialization of linked list

To create a new linked list, we first define the structure of a linked list, which contains the data part and pointer part. The data can be defined as void * type, so that we can receive any type of data.

typedef struct ListNode
{
	void* date;  //Data domain
	struct ListNode* next; //Pointer field, pointing to the next node
}ListNode;

After defining the structure of the linked list, we also need to initialize a head node of the linked list, that is, phead in the figure above, to facilitate our operations of adding, deleting, modifying and querying. Here are two functions to do this. First, we need to write a function to create a new node, and then create a head node.

//Create a new node
ListNode* BuyNode(void* newdate)
{
	//Make room for new nodes
	ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
	//Assign a value to the new node
	newNode->date = newdate;
	newNode->next = NULL;
	return newNode;
}
//Initialize the linked list. Create header node
ListNode* InitList()
{
	void* date = NULL;
	ListNode* phead = BuyNode(date);
	phead->date = NULL;
	phead->next = NULL;

	return phead;
}

2.3 inserting nodes

The insertion of linked list is generally divided into head insertion and tail insertion, as well as the insertion at any position. Here I will write an insertion at any position. To insert a node into a pos location, we must first find the previous node posPrve of the location, the new node newNode - > next points to the pos location, and then make posPrve - > next point to the new node newNode. As shown in the figure below

Let's look at the specific code

//In the insertion operation, we need to use the length of the linked list, so first write a function to find the length of the linked list.
//This is relatively simple. Just traverse the linked list
int lenthOfList(ListNode* phead)
{
	int count = 0;
	while (phead)
	{
		phead = phead->next;
		count++;
	}
	return count;
}

void InsertList(ListNode* phead, int pos, void* date)
{
	assert(phead);
	//Judge the effectiveness of pos position
	if (pos < 0)
	{
		return;
	}
	if (date == NULL)
	{
		return;
	}
	//Create a new data node
	ListNode* newNode = BuyNode(date);
	//Get the length of the linked list
	int lenth =  lenthOfList(phead);
	//If the pos position is greater than the length of the linked list, the tail insertion is carried out, which is up to you
	if (pos > lenth) 
	{
		ListNode* last = phead;
		//Traverse to the end of the linked list
		while (last->next)
		{
			last = last->next;
		}
		//Tail insertion
		last->next = newNode;
		newNode->next = NULL;
	 	return;
	}
	
	ListNode* cur = phead;
	//Traverse to the previous position of pos position
	for (int i = 1; i < pos; i++)
	{
		cur = cur->next;
	}
	                                                                                                                                               
	newNode->next = cur->next;
	cur->next = newNode;
}

2.4 deleting nodes

To delete a node, two methods are provided: one is to delete by setting a location, and the other is to delete by data content.

2.4.1 delete by location

First, we need to find the node at the POS location, record the previous node at the POS location and the node is posPrve, and then make pospre - > next point to pos - > next.

void removeByPosList(ListNode* phead, int pos)
{
	assert(phead);
	//Get the length of the linked list
	int lenth = lenthOfList(phead);
	//Judge position validity
	if (pos<0 || pos>lenth)
	{
		return;
	}
	ListNode* posPrve= phead;
	//Traverse to the previous node of the linked list
	for (int i = 1; i < pos; i++)
	{
		posPrve= posPrve->next;
	}
	//Get the node to delete
	ListNode* posNode = posPrve->next;
	//Delete operation
	posPrve->next = posNode ->next;
	//Free up space for deletion location
	free(posNode);
	posNode == NULL;
}

2.4.2 deleting nodes through data

To delete a node through data, we must first find the node in the linked list that is the same as the node data we want to delete, and then delete it.
So how can we find the node with the same data? Because the data stored in the structure of our linked list is void * data, we can use a function pointer as a callback function to judge. Next, I will introduce how to use function pointers

void removeByDateList(ListNode* phead, void* date, bool(*myCompar)(void*,void*))
{
	assert(phead);
	ListNode* cur = phead;
	while (cur)
	{	
	//Records the previous node of the current node
		ListNode* curPrve = cur;
		cur = cur->next;
		//Judge whether the data is the same, and then delete it
		if (myCompar(cur->date,date))
		{
			curPrve->next = cur->next;
			free(cur);
			cur = NULL;
			break;
		}
	}
}

Some people may not know how to write callback functions, so let me list a self-defined data type as an example

//Define a user-defined data type if the data type is stored in the linked list
//Then you can use this function as a callback function to judge the linked list data
struct Person
{
	char name[64];
	int age;
};
//Write a function to judge whether the data is the same. If the data is the same, it returns true, otherwise it returns false
bool myCompar(void* date1, void* date2)
{
	struct Person* p1 = date1;
	struct Person* p2 = date2;
	if ((strcmp(p1->name, p2->name) == 0) && (p1->age == p2->age))
	{
		return true;
	}
	return false;
}

2.5 print linked list

Because we define void * data here, the data in the linked list cannot be printed directly, and can only be printed through the callback function. Seeing this, some people may ask why to use void * type data. If you use void * type data, you need to provide callback functions for traversal and search. Isn't it more troublesome. In fact, it is not. You can receive any type of data with void * data. In this way, when we change the data type next time, we don't need to change the code frequently, which is more convenient

//Print information, used as a callback function to traverse the array
void myPrint(void* date)
{
	struct Person* p = date;
	printf("full name:%s  Age: %d\n", p->name, p->age);
}

void foreachList(ListNode* phead, void(*myforeach)(void*))
{
	assert(phead);
	ListNode* first = phead->next;
	while (first)
	{
		myforeach(first->date);
		first = first->next;
	}
}

2.6 empty linked list

Clearing the linked list is relatively simple, that is, delete all nodes in the linked list.
There are two ways to clear the linked list: one is not clear the header node, and the other is clear all.

2.6.1 unclear short node

void clearList(ListNode* phead)
{
	assert(phead);
	ListNode* cur = phead->next;
	while (cur)
	{
		ListNode* curNext = cur->next;
		free(cur);
		cur = curNext;
	}
	phead->next = NULL;
}

2.6.2 short clearing node

void destorList(ListNode* phead)
{
	assert(phead);
	clearList(phead);//Call the function written above
	free(phead);
	phead = NULL;
}

Topics: C data structure linked list