In-depth analysis of single linked list of data structure

In this article, you will use singly linked list proficiently , thoroughly play with singly linked list, and you will find that singly linked list is really simple.

First, let’s introduce the composition of the single-linked list . The single-linked list is composed of one or more independent nodes with discontinuous memory . Each node is a structure . There are two attributes inside the node : 1. The data stored in the node 2. The address of the next node.

Table of contents

code layout

1. Create a singly linked list

2. Print linked list

3. Linked list head node insertion

Four. Linked list tail node insertion

5. Delete the head node of the linked list

6. Delete the tail node of the linked list

Seven. Linked list node lookup

8. Modification of linked list nodes

9. Insert after the specified node in the linked list

10. Insert before the specified node in the linked list

11. Delete the node at the specified position of the linked list


code layout

  • Declare nodes and functions in the SingleList.h file
  • Implement the function in the SingleList.c file
  • Test the code in the   test.c file

1. Create a singly linked list

Create a singly linked list in the SingleList.h file

typedef struct SingleList
{
	datetype date;//存放数据
	struct SingleList* next;//存放下一个节点的地址
}SLT;

In order to facilitate the observation of the data in the linked list, we can write a function printSLT to facilitate the test code.

2. Print linked list

void printSLT(SLT* phead)
{
	SLT* cur = phead;//头节点备份
	while (cur != NULL)
	{
		printf("%d->", cur->date);//打印当前节点数据
		cur = cur->next;//节点后移
	}
	printf("NULL");//打印结尾
}

3. Linked list head node insertion

The insertion of the linked list, from the essential analysis, is nothing more than creating a new node ----> linking the new node with the linked list . As long as these two steps are done well, we can insert the function.

The first step of insertion is to create a new node. In order to reduce code redundancy , write a function to create a new node to complete this task.

SLT* buynewnode(datetype n)
{
	SLT* newnode = (SLT*)malloc(sizeof(SLT));//在堆上申请空间,防止处函数空间被销毁
	if (newnode == NULL)//判断是否申请成功
	{
		printf("malloc失败");
		return NULL;
	}
	newnode->date = n;//将节点数据初始化
	newnode->next = NULL;
	return newnode;//返回创建的节点的地址
}

The second step of insertion is to link the new node with the linked list .

Looking at the picture, if you want to link newnode with the original linked list, you need to make newnode->next point to *pphead (address of the head node), and change the address of the new head node to the address of newnode. code show as below

void pushhead(SLT** pphead, datetype n)
{
	SLT* newnode = buynewnode(n);//创建新节点
	//链接新节点
	newnode->next = *pphead;//newnode指向*pphead
	*pphead = newnode;//头节点地址改为newnode的地址
}

This reflects the role of the secondary pointer . To change the address of the head node, the address of the head node address must be passed over, and the address of the head node address must be dereferenced  , so that the address of the head node can be accessed, and then the address of the head node can be changed. 

Four. Linked list tail node insertion

The tail insertion logic is the same, only need to create a new node, link the new node . It needs to be discussed in two cases, 1, the linked list is empty . 2, the linked list is not empty . When the linked list is not empty, you need to find the tail node tail , and then link the tail node with the new node. When the linked list is empty, only the head node address needs to be changed to the new node address. code show as below

void pushback(SLT** pphead, datetype n)
{
	SLT* newnode = buynewnode(n);//创建新节点
	SLT* tail = *pphead;//使用tail找到尾节点
	if (tail != NULL)//链表不为空
	{
		while (tail->next != NULL)//利用尾节点特征:tail->next==NULL,找到尾节点
		{
			tail = tail->next;
		}
		tail->next = newnode;//链接尾节点与新节点
	}
	else//链表为空
	{
		*pphead = newnode;//把头节点地址改为新节点地址(二级指针作用)
	}
}

5. Delete the head node of the linked list

To delete a linked list node, first assert the linked list (empty linked list cannot be deleted), and secondly, to delete the head node, you only need to change the address of the head node to the address of the next node of the head node, and then release the space of the original head node.

void pophead(SLT** pphead)
{
	assert(*pphead);//断言链表,保证链表不为空
	SLT* tmp = *pphead;//备份原头节点地址,防止头节点地址改后找不到
	*pphead = (*pphead)->next;//把头节点地址改为头节点下一个节点的地址
	free(tmp);//释放原头节点空间,使用备份
}

When the linked list has only one node, this deletion method is also feasible.

6. Delete the tail node of the linked list

First, assert the linked list (empty linked list cannot be deleted). Secondly, if the linked list has two or more nodes, if you want to delete the tail node, you must first find the penultimate node (tail), and then release the tail node (tail ->next) memory space, the next to last node is set to NULL. If the linked list has only one node, you only need to release the head node memory space, and then change the head node address to NULL. code show as below

void popback(SLT** pphead)
{
	assert(*pphead);//断言链表,保证链表不为空
	SLT* tail = *pphead;//倒数第二个节点tail
	if (tail->next != NULL)//两个以及两个以上节点
	{
		while (tail->next->next != NULL)//找到倒数第二个节点
		{
			tail = tail->next;//找到下一个节点
		}
		free(tail->next);//释放尾节点空间
		tail->next = NULL;//倒数第二个节点的next置为空
	}
	else//一个节点
	{
		free(*pphead);//直接释放节点空间
		*pphead = NULL;//将头节点地址改为空
	}
}

Seven. Linked list node lookup

The function of the linked list node lookup is to find the node storing the specified date and return the address of the node. The specific code is as follows, and the comments are very clear.

SLT* SLTfind(SLT* phead,datetype n)
{
	SLT* cur = phead;//备份头节点地址
	while (cur->date!=n)//循环遍历找到cur->date==n的节点cur
	{
		if (cur->next == NULL)//如果找到尾节点还没找到则返回NULL
			return NULL;

		cur = cur->next;
	}
		return cur;//尾节点前,提前找到则返回这个节点地址
}

8. Modification of linked list nodes

The function to be realized by modifying the linked list node is to modify the data of the node. If you want to change the data of the node whose data is n to m, you need to find the address of the node whose data is n first, and then change it to m.

void modifySLT(SLT* phead, datetype n,datetype m)//数据为n的节点数据改为m
{
	SLT* pos = SLTfind(phead, n);//找到date==n的节点的地址
	pos->date = m;//该节点数据改为m
}

9. Insert after the specified node in the linked list

The essence of inserting a node is to create a new node and link the new node with the linked list. Therefore, to insert after the specified position, you only need to link pos->next with the new node, and then link the new node with the node behind the original pos. (note the sequence problem)

void pushafterpoint(SLT* pos, datetype n)
{
	SLT* newnode = buynewnode(n);//创建新节点
    //链接新节点
	newnode->next = pos->next;//新节点的next存放pos位置节点的下一个节点地址
	pos->next = newnode;//pos指向新节点
}

10. Insert before the specified node in the linked list

The linked list is inserted before the specified position, which is essentially an insertion, but the details of linking new nodes are different. Note: If the specified position is the head node, then the insertion before the specified position is the head insertion, so write it separately.

void pushbehindpoint(SLT** pphead, SLT* pos, datetype n)
{
	SLT* newnode = buynewnode(n);//创建新节点
	if (pos == *pphead)//如果指定位置是头节点,头插
	{
		*pphead = newnode;
		newnode->next = pos;
	}
	else
	{
		SLT* tail = *pphead;//备份头节点地址
		while (tail->next != pos)//找到指定位置的上一个节点
		{
			tail = tail->next;
		}
        //在上一个节点与pos之间链接新节点
		tail->next = newnode;//上一个节点指向新节点
		newnode->next = pos;//新节点指向指定位置节点
	}
}

11. Delete the node at the specified position of the linked list

First of all, it is necessary to assert the linked list (the empty linked list cannot be deleted). The function to be realized by this function is to delete the node at the specified position. The steps are: link the node before the specified position with the node after the specified position , and then release the memory space of the node at the specified position. 

void poppoint(SLT** pphead, SLT* pos)
{
	assert(*pphead);//保证链表不为空
	SLT* cur = *pphead;//备份pphead
	if (pos == *pphead)//如果指定位置是头节点,头删
	{
		*pphead = (*pphead)->next;
		free(cur);
	}
	else
	{
		while (cur->next != pos)//找到指定位置之前的节点
		{
			cur = cur->next;
		}
		//链接指定位置之前与之后
		cur->next = pos->next;
		//释放指定位置内存空间
		free(pos);
	}
}

At this point, the basic operation of the single linked list is almost finished, but if you want to apply it proficiently and integrate it, you need to practice more and do some OJ related to the linked list to strengthen your understanding. I believe the progress will be obvious.

Guess you like

Origin blog.csdn.net/2301_76144863/article/details/130457116