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; }