(Super detailed!) [C language] Addition, deletion, checking and modification of singly linked list (with illustrations and source code)

Single linked list learning navigation

I. Introduction

2. Preparation work

1. Simple understanding of the operating principle of singly linked list

2. Regional editing

 3. SList.h header file reference area

1. Creation of singly linked list nodes

2. Declaration of singly linked list function function

4. SListTest.c test area

5. SList.c function implementation area

1. Dynamically apply for a node

2. Single linked list printing

3. Single linked list tail insertion

4.Single linked list header plug-in

5.Delete the tail of singly linked list

6.Delete the header of single linked list

7.Singly linked list search

8.Singly linked list is inserted after pos (specified) position

9. The singly linked list is deleted after the pos (specified) position

10. Destroy singly linked list

6. Source code

1.SList.h source code

2.SList.c source code

 7. Conclusion


I. Introduction

This article describes my process and understanding of linked list learning, and is suitable for novices to learn and communicate. The content is just like the title. I will use drawings and screenshots to lead you to better understand the structure of a single linked list, learn and use its add, delete, check and modify functions. (shown by VS2019 compiler)

2. Preparation work

1. Simple understanding of the operating principle of singly linked list

 As shown in the figure above, a singly linked list is a form of placing a new structure pointer in the structure, and using the address of the next structure to find the data in the structure. Compared with the sequential list, the linked list has discontinuous storage of data, which is convenient Modified features. However, the shortcomings of a singly linked list are also obvious. It can only be traversed from the first node, which is quite limited.

2. Regional editing

The purpose of this is to better understand the code. I also mentioned it in the previous article, but modularity looks clear and is more conducive to our understanding, use, and modification of the code. (Also beautiful...)

 3. SList.h header file reference area

1. Creation of singly linked list nodes

In this file, we define the linked list structure, set int as the storage form of the data in the linked list (for convenience of display), and add the address of the next node to the node. Redefine the linked list to facilitate the use of this structure.

#define SLTDateType int

typedef struct SListNode
{
	SLTDateType Data;
	struct SListNode* Next;
}SListNode;

2. Declaration of singly linked list function function

Just declare these functions in the header file and use them directly. List the goals first, and then we will implement them one by one.

// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);

// 单链表打印
void SListPrint(SListNode* phead);

// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);

// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);

// 单链表的尾删
void SListPopBack(SListNode** pplist);

// 单链表头删
void SListPopFront(SListNode** pplist);

// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);

// 单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x);

// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos);

// 单链表的销毁
void SListDestroy(SListNode* plist);

Among them, the parameters passed in by some functions are secondary pointers. Why? Because the parameter passed in by the function is a temporary copy of the actual parameter, if a first-level pointer is passed in, then we can change the data pointed to by this pointer, and what if we want to change the address of this pointer? For the same reason, we need a pointer to the address of this pointer, which is a secondary pointer.

4. SListTest.c test area

This area is mainly a test module for the written functional functions to judge the correctness and perfection of the functions.

int main()
{
	SListNode* List = NULL;

	SListTest1(List);
	SListTest2(List);
	SListTest3(List);
	SListTest4(List);
	SListTest5(List);
	SListTest6(List);
	SListTest7(List);

	return 0;
}

It is similar to the menu, but it lacks a more magnificent interface, because writing the menu may affect the efficiency of our debugging. It is a better choice to complete the menu interface after the functional functions are implemented and debugged. The test area can be defined by yourself, and I will also combine this area below to show the implementation effect of the function.

5. SList.c function implementation area

1. Dynamically apply for a node

You can use the malloc and calloc functions to apply for linked list nodes. Here we use malloc. Remember to check whether the return value is empty.

//动态申请链表节点
SListNode* BuySListNode(SLTDateType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		perror("BuySListNode::malloc");
		return;
	}
	newnode->Data = x;
	return newnode;
}

Here you can also leave the next address of the node blank before returning to the node. Initialization is also a good choice. You can choose based on your personal needs.

2. Single linked list printing

Pass the first node into the function, iterate through the data stored in each node one by one through the next pointer in the node, and print it out. Just stop when the last node is empty.

//打印链表
void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->Data);
		cur = cur->Next;
	}
	printf("NULL\n");
}

3. Single linked list tail insertion

There are two situations that need to be considered for tail insertion. The first is when the linked list is empty. In this case, you can directly point the linked list to the opened node. The second situation is when it is not empty. This situation is more complicated. Let’s draw a picture to solve it:

 The addresses are all made up. This is the principle. The code is implemented as follows:

//尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
    //判断是否为空链表
	if (*pplist==NULL)
	{
		*pplist = BuySListNode(x);
		(*pplist)->Next = NULL;
	}
	else
	{
		//查找尾部
		SListNode* ptr = *pplist;
		while (ptr->Next)
		{
			ptr = ptr->Next;
		}
		//插入
		ptr->Next = BuySListNode(x);
		ptr->Next->Next = NULL;
	}
}

The effect of combining the printing linked list function is as follows:

4.Single linked list header plug-in

The implementation of head insertion is the same as tail insertion, divided into two situations: empty linked list and non-empty linked list. The difference between the two lies in the non-empty situation. The header plug demonstration is as shown in the figure:

It turns out that there is a non-empty linked list without a head, and pplist points to the address of the head node.

The demonstration of inserting the non-empty linked list of the head node is as shown in the figure above, and the code implementation is as follows.

//头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
	if (*pplist == NULL)
	{
		*pplist = BuySListNode(x);
		(*pplist)->Next = NULL;
	}
	else
	{
		SListNode* ptr = BuySListNode(x);
		ptr->Next = *pplist;
		*pplist = ptr;
	}
}

The effect is as follows:

5.Delete the tail of singly linked list

Tail deletion is divided into three situations:

The first is whether the linked list is empty. If it is empty, you can choose to report an error or return directly (how to delete if there is no content...);

The second case is when the linked list is not empty, but there is only one node. In this case, we need to empty the linked list directly;

The third case is a multi-node situation. At this time, we need to empty the node before the NULL node. The node before the NULL node is needed to judge, because the unused memory needs to be freed. This situation is shown in the figure below.

The specific implementation is as follows:

//尾删
void SListPopBack(SListNode** pplist)
{
	assert(pplist);
	assert(*pplist);
	
	if ((*pplist)->Next == NULL)
	{
		//单个链表块
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		//2个及以上链表块
		SListNode* ptr = *pplist;
		while (ptr->Next->Next)
		{
			ptr = ptr->Next;
		}
		free(ptr->Next);
		ptr->Next = NULL;
	}
}

The effect is as follows:

6.Delete the header of single linked list

There are only two situations that need to be considered for header deletion.

The first is to determine whether the linked list is empty;

In the second method, regardless of whether there are multiple nodes or not, the pointer pointing to the address of the head node will move backward to the address of the next node, so there is no need to consider whether the next node is empty.

 The code is implemented as follows:

//头删
void SListPopFront(SListNode** pplist)
{
	assert(pplist);
	assert(*pplist);

	SListNode* Del = *pplist;
	*pplist = (*pplist)->Next;
	free(Del);
	Del = NULL;
}

The specific effect is shown in the figure:

7.Singly linked list search

Find the target node and return the address of the node. Just use a first-level pointer to pass the value. Because the return value is a first-level pointer, this type of function method can also replace the use of the above second-level pointer (I personally think this is not good-looking) .

The search requires traversal. Unless the target node is found, it will stop until NULL and return directly to the search node.

//查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	SListNode* find = plist;
	while (find && find->Data != x)
		find = find->Next;
	return find;
}

The effect is as follows:

8.Singly linked list is inserted after pos (specified) position

This function is very similar to the head insertion function with multiple nodes, but this function does not need to change the position of the head node pointer, so just pass in the first-level pointer.

Before inserting, you need to determine whether the passed in null pointer is a null pointer, and then insert it. However, the order of writing must be correct, otherwise the original address may be lost?

//在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
	assert(pos);
	SListNode* next = pos->Next;

	SListNode* newnode = BuySListNode(x);
	pos->Next = newnode;
	newnode->Next = next;
}

The effect is as follows:

9. The singly linked list is deleted after the pos (specified) position

This function is relatively simple, just pay attention to whether the passed value is a null pointer and whether the next node pointed to is null.

If you don't judge the latter, you will be accessing illegally... I have to say that linked lists are too many pitfalls for beginners.

//删除pos位置之后的值
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	if (pos->Next == NULL)
		return;
	else
	{
		SListNode* NNext = pos->Next->Next;
		free(pos->Next);
		pos->Next = NNext;
	}
}

The effect is as follows:

10. Destroy singly linked list

Similar to the destruction of the sequence list, the difference is that the former needs to be freed, and the pointers of the linked list nodes are traversed.

//销毁
void SListDestroy(SListNode* plist)
{
	assert(plist);
	SListNode* Del = plist;
	while (Del)
	{
		plist = plist->Next;
		free(Del);
		Del = plist;
	}
}

6. Source code

1.SList.h source code

#pragma once

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#define int SLTDateType 

typedef struct SListNode
{
	SLTDateType Data;
	struct SListNode* Next;
}SListNode;

// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);

// 单链表打印
void SListPrint(SListNode* phead);

// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);

// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);

// 单链表的尾删
void SListPopBack(SListNode** pplist);

// 单链表头删
void SListPopFront(SListNode** pplist);

// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);

// 单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x);

// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos);

// 单链表的销毁
void SListDestroy(SListNode* plist);

2.SList.c source code

#include "SList.h"

//动态申请链表节点
SListNode* BuySListNode(SLTDateType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		perror("BuySListNode::malloc");
		return;
	}
	newnode->Data = x;
	return newnode;
}

//打印链表
void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->Data);
		cur = cur->Next;
	}
	printf("NULL\n");
}

//尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
	if (*pplist==NULL)
	{
		*pplist = BuySListNode(x);
		(*pplist)->Next = NULL;
	}
	else
	{
		//查找尾部
		SListNode* ptr = *pplist;
		while (ptr->Next)
		{
			ptr = ptr->Next;
		}
		//插入
		ptr->Next = BuySListNode(x);
		ptr->Next->Next = NULL;
	}
}

//头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	if (*pplist == NULL)
	{
		*pplist = BuySListNode(x);
		(*pplist)->Next = NULL;
	}
	else
	{
		SListNode* ptr = BuySListNode(x);
		ptr->Next = *pplist;
		*pplist = ptr;
	}
}

//尾删
void SListPopBack(SListNode** pplist)
{
	assert(pplist);
	assert(*pplist);
	
	if ((*pplist)->Next == NULL)
	{
		//单个链表块
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		//2个及以上链表块
		SListNode* ptr = *pplist;
		while (ptr->Next->Next)
		{
			ptr = ptr->Next;
		}
		free(ptr->Next);
		ptr->Next = NULL;
	}
}

//头删
void SListPopFront(SListNode** pplist)
{
	assert(pplist);
	assert(*pplist);

	SListNode* Del = *pplist;
	*pplist = (*pplist)->Next;
	free(Del);
	Del = NULL;
}

//查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	SListNode* find = plist;
	while (find && find->Data != x)
		find = find->Next;
	return find;
}

//在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
	assert(pos);
	SListNode* next = pos->Next;

	SListNode* newnode = BuySListNode(x);
	pos->Next = newnode;
	newnode->Next = next;
}

//删除pos位置之后的值
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	if (pos->Next == NULL)
		return;
	else
	{
		SListNode* NNext = pos->Next->Next;
		free(pos->Next);
		pos->Next = NNext;
	}
}

//销毁
void SListDestroy(SListNode* plist)
{
	assert(plist);
	SListNode* Del = plist;
	while (Del)
	{
		plist = plist->Next;
		free(Del);
		Del = plist;
	}
}

 7. Conclusion

There is still a lot of content in linked lists for novices, and pitfalls are everywhere, so you need to be careful and patient. In addition to singly linked lists, there are many other forms, but they are all similar. You can figure it out by rubbing it with your hands a few times. Anyway, I will work hard with you all!

Guess you like

Origin blog.csdn.net/qq_74641564/article/details/129331143