[Data Structure Getting Started Guide] Singly Linked List

Overview:

 Since the insertion and deletion of elements in the sequential table needs to move a large amount of data, the operating efficiency is reduced. Therefore, another data structure- linked list is introduced . Linked lists are further divided into singly linked lists and double linked lists. The singly linked list has a simple structure and is generally not used to store data alone. In practice, it is more of a substructure of other data structures, such as hash buckets, adjacency lists of graphs, and so on. In addition, this structure appears a lot in written test interviews.


1. Definition of singly linked list

 The singly linked list uses a set of arbitrary storage units to store the data elements in the linear list, and does not need to use storage units with continuous addresses, so it does not require that two elements that are logically adjacent are also physically adjacent.

constitute:

 A singly linked list consists of a series of nodes, and each node contains two parts: a data field (storing data elements) and a pointer field (storing the address of the next node).

typedef int SLTDateType;
typedef struct SListNode
{
    
    
	SLTDateType date;//数据域
	struct SListNode* next;//指针域
}SLTNode;

Features:

  1. The nodes of the singly linked list are discretely distributed in memory, and they are connected in series through pointers.
  2. Singly linked list can dynamically allocate memory space, and can flexibly insert and delete nodes as needed.
    insert image description here

2. The creation of singly linked list

typedef int SLTDateType;
typedef struct SListNode
{
    
    
	SLTDateType date;//数据域
	struct SListNode* next;指针域
}SLTNode;

First create a structurestruct SListNodeUsed to store data and pointers.
Considering the convenience of subsequent data type modification, we willstruct SListNodeRename with typedef toSLNode.
At the same time, in order to facilitate the connection of different data types by calling the interface in the future, we set the type of the data fieldintrenamed toSLDateType. (Subsequent storage of non-stop data only needs to be modified here)


3. Implementation of various interfaces of single linked list

1. Dynamically apply for a node

 When a new node is to be inserted later, a node must first be created to store relevant information and connected to a suitable position in the singly linked list.

Code:

SLTNode* BuySListNode(SLTDateType x)
{
    
    
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
    
    
		perror("malloc");
		exit(-1);
	}
	newnode->date = x;
	newnode->next = NULL;
	return newnode;
}

2. Singly linked list printing

To print a singly linked list, we only need to record the head node, then traverse and access, and print in sequence.

Code:

void SLTPrint(SLTNode* phead)
{
    
     
	SLTNode* cur = phead;
	while (cur)
	{
    
    
		printf("%d->", cur->date);
		cur = cur->next;
	}
	printf("NULL\n");
}

3. Rear plug

There are two cases of tail insertion: no node and node.
①: No node: Create a new node, and then the head pointer points to the new node.
②: There are nodes: traverse to find the last node, and then point its next node to the new node

Code:

//由于尾插第一种情况需要改变结构体指针,所以我们要传结构体二级指针
void SLTPushBack(SLTNode** pphead, SLTDateType x)
{
    
    
	assert(pphead);
	SLTNode* newnode = BuySListNode(x);
	if (*pphead == NULL)//没有节点
	{
    
    
		*pphead = newnode;
	}
	else
	{
    
    
	    //有节点
		SLTNode* tail = *pphead;
		while (tail->next)//遍历找到最后一个节点
		{
    
    
			tail = tail->next;
		}
		//尾插
		tail->next = newnode;
	}
}

4. Plug

Plugging in is relatively simple. Regardless of whether the original linked list has nodes or not, just insert a new node.

Code:

//由于头插会改变头指针,所以我们传二级指针
void SLTPushFront(SLTNode** pphead, SLTDateType x)
{
    
    
	assert(pphead);
	SLTNode* newnode = BuySListNode(x);//新节点
	//头插
	newnode->next = *pphead;
	*pphead = newnode;
}

5. Tail deletion

The situation in tail deletion 3:
①: First of all, it is necessary to determine whether there are nodes in the linked list that can be deleted.
②: There is only one node in the linked list. A node is relatively simple, just set the head pointer to empty, and then release the head node.
③: There are multiple nodes in the linked list. Multiple nodes, first traverse to find the previous node of the tail node. Then set its pointer field to NULL, and release the tail node.

Code:

void SLTPopBack(SLTNode** pphead)
{
    
    
	assert(pphead);
	//1.空
	assert(*pphead);

	if ((*pphead)->next == NULL)//2.一个节点
	{
    
    
		(*pphead)->next = NULL;
	}
	else
	{
    
    
		//3.多个节点
		SLTNode* tail = *pphead;
		遍历找到尾节点的前一个节点
		while (tail->next->next)
		{
    
    
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}

}

6. Head delete

Head deletion is divided into two situations:
①: First, determine whether there are nodes in the linked list that can be deleted.
②: There are still nodes in the linked list that can be deleted. Save the second node first, and release the head node. And point the head pointer to the second node.

Code:

void SLTPopFront(SLTNode** pphead)
{
    
    
	assert(pphead);
	//空
	assert(*pphead);
	//非空
	SLTNode* newnode = (*pphead)->next;//保存第二个节点
	free(*pphead);//释放头节点
	*pphead = newnode;
}

7. Find

Finding is the same as printing, just traverse and access directly. The return address was found, but a null pointer was returned if it was not found.

Code:

SLTNode* SLTFind(SLTNode* phead, SLTDateType x)
{
    
    
	SLTNode* cur = phead;
	while (cur)
	{
    
    
		if (cur->date == x)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

8. Insert x before pos

In the linked list, no matter whether it is a single linked list or a double linked list, inserting a new node somewhere is generally inserted forward by default.
There are two situations for forward insertion:
①: The position of pos is the first node. Can be reused beforeplug interfaceaccomplish.
②: Traverse the access linked list to find the node prev before pos, and then connect pos, prev, and the new node.

Code:

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
    
    
	assert(pphead);
	assert(*pphead);
	if (*pphead == pos)
	{
    
    
		SLTPushFront(pphead, x);//头插
	}
	else
	{
    
    
		SLTNode* prev = *pphead;
		//遍历找到pos前一个节点
		while (prev->next != pos)
		{
    
    
			prev = prev->next;
		}
		SLTNode* newnode = BuySListNode(x);
		//prev,newnode,pos三个节点链接
		prev->next = newnode;
		newnode->next = pos;
	}
}

9. Insert x after pos

Inserting x before pos is relatively complicated. So if there is no special requirement, post-pos insertion can be used. So we provide pos back plug interface here.

Code:

void SLTInsertAfter(SLTNode* pos, SLTDateType x)
{
    
    
	assert(pos);

	SLTNode* newnode = BuySListNode(x);
	//后插
	newnode->next = pos->next;
	pos->next = newnode;
}

10. Delete the value of pos position

There are two situations for deleting the value of the pos position:
①: If pos is the head node, reuse the head delete interface.
②: Traverse to find the node prev before pos. Then link the previous node of pos to the next node, and release pos.

Code:

void SLTErase(SLTNode** pphead, SLTNode* pos)
{
    
    
	assert(pphead);
	assert(pos);

	if (*pphead == pos)
	{
    
    
		SLTPopFront(pphead);
	}
	else
	{
    
    
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
    
    
			prev = prev->next;
		}

		prev->next = pos->next;
		//free(pos);
	}
}

11. Delete the value after the pos position

To delete the value after the pos position, we first link pos and the two node pointers after pos, and release the node after pos. (To determine whether pos is a tail node)

Code:

void SLTEraseAfter(SLTNode* pos)
{
    
    
	assert(pos);
	//检查pos是否为尾节点
	assert(pos->next);

	SLTNode* posNext = pos->next;
	pos->next = posNext->next;

	free(posNext);
	posNext = NULL;
}

12. Destroy

Code:

void SLTDestory(SLTNode** pphead)
{
    
    
	assert(pphead);

	SLTNode* cur = *pphead;
	while (cur)
	{
    
    
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

4. All code display

List.h:

#pragma once

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


typedef int SLTDateType;
typedef struct SListNode
{
    
    
	SLTDateType date;
	struct SListNode* next;
}SLTNode;


void SLTPrint(SLTNode* phead);

SLTNode* BuySListNode(SLTDateType x);

void SLTPushBack(SLTNode** pphead, SLTDateType x);
void SLTPushFront(SLTNode** pphead, SLTDateType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);

SLTNode* SLTFind(SLTNode* phead, SLTDateType x);

//在pos之前插入x
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);
//在pos之后插入x
void SLTInsertAfter(SLTNode* pos, SLTDateType x);
//删除pos位置的值
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos位置之后的值
void SLTEraseAfter(SLTNode* pos);

//销毁
void SLTDestory(SLTNode** pphead)

List.h:

include "SList.h"


void SLTPrint(SLTNode* phead)
{
    
     
	SLTNode* cur = phead;
	while (cur)
	{
    
    
		printf("%d->", cur->date);
		cur = cur->next;
	}
	printf("NULL\n");
}


SLTNode* BuySListNode(SLTDateType x)
{
    
    
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
    
    
		perror("malloc");
		exit(-1);
	}
	newnode->date = x;
	newnode->next = NULL;
	return newnode;
}


void SLTPushBack(SLTNode** pphead, SLTDateType x)
{
    
    
	assert(pphead);
	SLTNode* newnode = BuySListNode(x);
	if (*pphead == NULL)
	{
    
    
		*pphead = newnode;
	}
	else
	{
    
    
		SLTNode* tail = *pphead;
		while (tail->next)
		{
    
    
			tail = tail->next;
		}
		tail->next = newnode;
	}
}


void SLTPushFront(SLTNode** pphead, SLTDateType x)
{
    
    
	assert(pphead);
	SLTNode* newnode = BuySListNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}


void SLTPopBack(SLTNode** pphead)
{
    
    
	assert(pphead);
	//1.空
	assert(*pphead);

	//2.一个节点
	//3.多个节点
	if ((*pphead)->next == NULL)
	{
    
    
		(*pphead)->next = NULL;
	}
	else
	{
    
    
		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
    
    
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}

}


void SLTPopFront(SLTNode** pphead)
{
    
    
	assert(pphead);
	//空
	assert(*pphead);
	//非空
	SLTNode* newnode = (*pphead)->next;
	free(*pphead);
	*pphead = newnode;
}

SLTNode* SLTFind(SLTNode* phead, SLTDateType x)
{
    
    
	SLTNode* cur = phead;
	while (cur)
	{
    
    
		if (cur->date == x)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
    
    
	assert(pphead);
	assert(*pphead);
	if (*pphead == pos)
	{
    
    
		SLTPushFront(pphead, x);
	}
	else
	{
    
    
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
    
    
			prev = prev->next;
		}
		SLTNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}



void SLTInsertAfter(SLTNode* pos, SLTDateType x)
{
    
    
	assert(pos);

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

void SLTErase(SLTNode** pphead, SLTNode* pos)
{
    
    
	assert(pphead);
	assert(pos);

	if (*pphead == pos)
	{
    
    
		SLTPopFront(pphead);
	}
	else
	{
    
    
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
    
    
			prev = prev->next;
		}

		prev->next = pos->next;
		//free(pos);
	}
}


void SLTEraseAfter(SLTNode* pos)
{
    
    
	assert(pos);
	//检查pos是否为尾节点
	assert(pos->next);

	SLTNode* posNext = pos->next;
	pos->next = posNext->next;

	free(posNext);
	posNext = NULL;
}

void SLTDestory(SLTNode** pphead)
{
    
    
	assert(pphead);

	SLTNode* cur = *pphead;
	while (cur)
	{
    
    
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/Zhenyu_Coder/article/details/132065111