In the sequence table, we understand the concept of sequence table and how to create a sequence table and its interface function to complete the functions of addition, deletion, query and modification. This paper will continue to introduce the content of linear storage, explain the concept of single linked list, and give the C language implementation of its interface function
Some disadvantages of sequence table:
In the sequence table stage, we learned that the sequence table is a continuous storage space in memory, and the elements are stored next to each other. Without much thinking, we can find some disadvantages of sequence table in practical application:
- In order to store dynamically, you need to create a dynamic linked list for data storage.
- In order to avoid frequent capacity expansion, when realloc is used to apply for space, it often directly applies for twice the current space, which inevitably wastes space.
- When inserting or deleting data, the whole sequence table needs to be moved, which is very inefficient.
- When the realloc function applies for memory space, there is a risk of application failure.
So some people consider using linked list to solve the above related problems.
What is a single linked list?
As the name suggests, a single linked list is a data storage type that is different from a sequential table and does not need to be continuously stored in memory. Each data element can be stored separately in memory. Data and data are connected with each other by means of next pointer, forming a whole like a "hinge" in structure. As shown in the figure, it is convenient for you to understand the structure of the single linked list more clearly:
The single linked list still takes a structure as the basic structure. Data is stored in data, and the next pointer of the structure stores the address of the next data. The next data element can be found by dereferencing the next pointer of the current data. A single linked list always starts with a header pointer to the first element and ends with a null pointer to the last element. In the above figure, we can find that the linked list does not need to be continuously stored in memory due to the addressing characteristics of the pointer.
Advantages of linked list:
Apply for space on demand and release space when not in use (more reasonable use of space)
Insert data in the head and middle without moving the data
Disadvantages of linked list:
Each data needs a pointer to store the node linking the data behind it
Random access is not supported (access the ith with subscript)
Unlike the sequence table,
The linked list starts with a header pointer, rather than simply using the materialization of a structure variable as a sequential list. Single linked list is maintained with pointers. The start of the linked list starts with a NULL structure pointer. The pointer is assigned, that is, the initialization is completed. There is no additional initialization function to initialize it.
Note: to understand the related concepts of NULL pointer, NULL pointer cannot be dereferenced. The NULL pointer stores 0x00000000, which cannot dereference and access any content. Therefore, all dereference operations of NULL pointer are wrong. However, the pointer storing NULL (i.e. NULL pointer) has an address, and the tail interpolation passes the address of the NULL pointer. The dereference of the address of the NULL pointer is valid, and the NULL value 0x00000000 is obtained.
Implementation of single linked list
Each node of the linked list needs to have the following functions:
1. Store data
2. Access the content stored in the next node
Therefore, for a single linked list, its contents are also defined by structure:
To facilitate changing data types, we can redefine int and other types as SLTDataType
//. h file #pragma once #include<stido.h> #include<stdlib.h> typedef int SLTDataType typedef struct SListNode { SLTDataType data;//Stored data struct SlistNode* next;//next pointer }SLTNode; //Auxiliary functions are used to create new nodes SLTNode* BuyListNode(SLTDataType x); //Print function void SListPrint(SLTNode* phead); //Tail insertion void SListPushBack(SLTNode** pphead,SLDataType x); //Head insert void SListPushFront(SLTNode** pphead,SLDataType x); //Tail deletion void SListPopBack (SLNode** pphead); //Header deletion void SListPopFront(SLNode** pphead); //Find function void SListFind(SLTNode* phead,SLTNodeType x); //Specify subscript insertion void SListInsert(SLTNode* phead,SLTNode *pos,SLTDataType x); //Specify a position after the subscript to insert void SListInsertAfter(SLNode* pos,SLTDatatpye x); //Erase elements at a specific location void SListErase(SLTNode** pphead, STLNode pos,SLTDataType x); //Erase a specific unknown element void SListEraseAfter(SLTNode* pos); //Destroy linked list void SlistDestory(SLTNode** pphead);
Implementation of interface function
//. h corresponding. c file //Auxiliary functions are used to create nodes SLTNode* BuyListNode(SLTDataType x) { SLTNode* newnode=(SLTNode*)malloc(sizeof(SLTNode)); if(newnode==NULL) { printf("There's not enough space"); exit(-1); } else { newnode->data=x; newnode->next=NULL; } return newnode; } //Print function void SListPrint(SLTNode* phead) { SLTNode*cur=phead; while(cur!=NULL) { printf("%d->",cur->data); cur=cur->next; } } //Tail interpolation function void SListPushBack(SLTNode** pphead, SLTDataType x) //Remember to use the secondary pointer to receive and maintain the phead of the linked list for addressing { SListNode* newnode=BuyListNode(x); if(*pphead==NULL)//Judge whether the stored in phead is empty, that is, judge whether the linked list has started { *pphead=newnode;//Let the header pointer point to the struct space maintained by the new node } else//This shows that there are elements in the linked list and you need to find the tail node { SLTNode* tail=*pphead; //The flag of the tail node is that next is empty //Find tail node while(tail->next !=NULL) { tail=tail->next; } tail->next=newnode; } } //Head interpolation function //There is no need to empty the header pointer during header insertion, just apply for space to create a node and give the header pointer void SListPushFront(SLTNode** pphead,SLTDataType x) { SListNode* newnode=BuyListNode(x); newnode->next=*pphead; *pphead=newnode; } //Tail deletion void SListPopBack (SLNode** pphead) { if(*pphead==NULL)//When the linked list is empty, 0 is returned directly. Here, assert can also be used to ensure that the linked list is not empty { return 0; } if((*phead)->next ==NULL)//When there is only one node { free(*pphead); *pphead=NULL; } else { SLNode* prev=NULL; SLNode* tail= *pphead; while(tail->next!=NULL) { prev=tail; tail=tail->next; } free(tail);//free the contents of the last node tail=NULL; //Set the tail pointer to the last node to NULL, but the next pointer to the penultimate node in the linked list is not modified to NULL because the tail is a random value after being free //Therefore, set the next of the penultimate node to NULL to complete the tail deletion. prev->next=NULL; //The penultimate next pointer is set to null by accessing the penultimate next pointer of the penultimate structure through the next pointer of the penultimate structure } /*//You can also use this method SLTNode* tail=*pphead; while(tail->next->next) { tail=tail->next; } //When calling out the loop, tail is the penultimate node //Remove the free of the next position of the tail free(tail->next); //tail As the penultimate node, its next pointer needs to be set to null tail->next=NULL; */ } //Header deletion void SListPopFront(SLNode** pphead) { if(*pphead==NULL) { return 0; } SLNode* head =*pphead->next; free(*pphead); *pphead=head; } //Find function STLNode* SListFind(SLTNode* phead,SLTNodeType x) { SLTNode* pf=phead; /* while(pf->data!=x) { pf=pf->next; } if(pf->data==x) { retrun 1; } else { return -1; }*/ while(pf) { if(of->data==x) { retunn pf; } else { pf=pf->data; } } return NULL; } //Specify Pos position insert (forward) void SListInsert(SLTNode** pphead, STLNode * pos,SLTDataType x) { assert(pphead); assert(pos); STLNode* newnode=BuyListNode(x); //Find pos location STLNode* posPrev=*pphead; while(posPrev->next!=pos) { posPrev=posPre->next; } posPrev->next=newnode; newnode->next=pos; } //Insert after pos void SListInsertAfter(SLTNode* pos, SLTDateType x) { assert(pos); SLTNode* newnode = BuyListNode(x); newnode->next = pos->next; pos->next = newnode; } //Specified position erase (erase after traversal) void SListErase(SLTNode** pphead, SLTNode* pos) { assert(pphead); assert(pos); if (*pphead == pos) { /**pphead = pos->next; free(pos);*/ SListPopFront(pphead); } else { SLTNode* prev = *pphead; while (prev->next != pos) { prev = prev->next; } prev->next = pos->next; free(pos);//Destroy pos in the filing table and set the space maintained by pos as a random value //pos = NULL; } } //Specify pos location to delete (delete after pos location) void SListEraseAfter(SLTNode* pos) { assert(pos); assert(pos->next); SLTNode* next = pos->next;//Create the next structure pointer and hand over the structure of the next position of the pos to it for maintenance. The purpose is to find the next position of the pos so that the pos can directly point to the next one, and then you can delete the content after the pos pos->next = next->next;//Assign a value to the next pointer in the space maintained by the next structure pointer (the next pointer of the next pos) to the next pos, and destroy the next position of the pos free(next); //next = NULL; } //Destroy void SListDestory(SLTNode** pphead) { assert(pphead); SLTNode* cur = *pphead; while (cur) { SLTNode* next = cur->next; free(cur); cur = next; } *pphead = NULL; }
//test the. c file void Test_list() { SLTNode* plist = NULL; //The single linked list starts with a structure pointer to create the whole linked list, so it echoes the need to pass the secondary pointer to modify the value of the primary pointer in the above. SListPushBack(&plist, 1); SListPushBack(&plist, 2); SListPushBack(&plist, 3); SListPushBack(&plist, 4); SListPrint(plist); SListPushFront(&plist, 1); SListPushFront(&plist, 2); SListPushFront(&plist, 3); SListPushFront(&plist, 4); SListPrint(plist); //You can try calling other interface functions and pay attention to the parameter types passed! } int main() { Test_list(); }
Summary
For a single linked list, it does not need to be stored continuously in memory, which realizes the convenience of storage. However, due to this feature, it can not be accessed randomly through subscript. The materialization process of the single linked list is realized by a structure pointer. When implementing the interface function, because the head pointer is a first-class pointer, if you want to modify the value of the space maintained by the first-class pointer, you need to pass the address of the first-class pointer, receive it with the second-class pointer, and modify the structure space maintained by the head pointer by dereferencing the second-class pointer. Because each node of the single linked list is opened up through the malloc function, don't forget to destroy it at the end to prevent unpredictable errors such as wild pointers.