Introduction to data structure (2) - singly linked list (add, delete, check, modify)

1. The concept of singly linked list

Concept: Linked list is a non-continuous and non-sequential storage structure in physical storage structure , but linked list is logically continuous and sequential, and the logical order of data elements is realized through the order of pointer connection in the linked list.

1.2 Structure of linked list

Let's redefine a new type called SLDataType for int. Here we want to explain that if we want to change the data type, we can change it directly here, without changing them one by one in the program.

 Here, SLTDataType data is used to store data, and *next is essentially a pointer, which actually stores the address of the next data , and is also the main part of the "bridge" in the single linked list

We actually store it like this, the address of the next memory is stored in a memory block


 2. Implementation of singly linked list

Let's give everyone the declaration of the function first.

#pragma once
#include<string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

void SLTPrint(SLTNode* phead);//打印单链表i
void SLPushFront(SLTNode** pphead, SLTDataType x);//头插
void SLPushBack(SLTNode** pphead, SLTDataType x);//尾插

void SLPopFront(SLTNode** pphead);//头删
void SLPopBack(SLTNode** pphead);//尾删

void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在pos位置之前插入
void SLInsertAfter(SLTNode* pos, SLTDataType x);//在pos后面插入

void SLErase(SLTNode** pphead, SLTNode* pos);//单链表结点删除
void SLEraseAfter(SLTNode* pos);//结点后面删除

2.1 Memory development

Here I think there is no need to say more, directly apply for space in the memory to open up a memory block

SLTNode* BuyLTNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

2.2 tail plug

When we perform tail insertion, there are two situations. The first situation is that what you pass is a null pointer, then we need to open up a space for the plist in pphead to store the address of this space.

The second case: If the passed here is not a null pointer, then we have to create a tail (let tail replace pphead to go one by one), play the role of link, and then let the newly opened memory address be stored in the tail behind, let tail point to the next node until it ends when it is NULL

void SLPushBack(SLTNode** pphead, SLTDataType x)
{
    //申请内存
	SLTNode* newnode = BuyLTNode(x);
    
    //第一个情况
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
    
    //第二个情况
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

2.3 head plug

The way we want to implement head insertion is the opposite of tail insertion, that is, let the address of pphead be assigned to the space next to our newly created memory block, so that we have realized a process of finding the old memory from the new memory, and then we will transfer the new memory to the old memory. The address is assigned to our pphead to make the pointer point to the address of the new memory block, thus forming a loop of head insertion

void SLPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);

	newnode->next = *pphead;
	*pphead = newnode;
}

2.4 tail deletion

Here is the same as before, what is the core idea? The core idea is to make the pointer to the last memory block NULL and release the last memory block.

void SLPopBack(SLTNode** pphead)
{
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else 
	{
		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}

		free(tail->next);
		tail->next = NULL;
	}
}

2.5 head delete

void SLPopFront(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
}

2.6 Insert in the middle (before pos)

We write a while loop here to first find the position you want to insert. At this time, we create a space so that the pointer in front of the position you want to insert points to your new space, and the tail of this new space points to the address of your original position before. This completes the middle insertion


void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuyLTNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}

}

2.7 Insert in the middle (after pos)

When we find the position of pos, let the memory address next to it be stored in the address next to the new memory, and then let the address of the new memory be assigned to the position next to pos, so that the middle insertion is completed

void SLInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

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

2.8 Delete node

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

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

2.9 Delete the following nodes

void SLEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLTNode* next = pos->next;
	pos->next = next->next;
	free(next);
}

2.10 Print singly linked list

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

3. Code summary

SList.c

#include "SList.h"

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

SLTNode* BuyLTNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

void SLPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);

	newnode->next = *pphead;
	*pphead = newnode;
}

void SLPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);

	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

void SLPopFront(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
}

void SLPopBack(SLTNode** pphead)
{
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else 
	{
		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}

		free(tail->next);
		tail->next = NULL;
	}
}

void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuyLTNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}

}

void SLInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

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

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

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

void SLEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLTNode* next = pos->next;
	pos->next = next->next;
	free(next);
}

SList.h

#pragma once
#include<string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

void SLTPrint(SLTNode* phead);//打印单链表i
void SLPushFront(SLTNode** pphead, SLTDataType x);//头插
void SLPushBack(SLTNode** pphead, SLTDataType x);//尾插

void SLPopFront(SLTNode** pphead);//头删
void SLPopBack(SLTNode** pphead);//尾删

void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在pos位置之前插入
void SLInsertAfter(SLTNode* pos, SLTDataType x);//在pos后面插入

void SLErase(SLTNode** pphead, SLTNode* pos);//单链表结点删除
void SLEraseAfter(SLTNode* pos);//结点后面删除

I will not write the content of test.c here


The above is the article sharing of this single-linked list. If you like it, please support it. Thank you for your support.


おすすめ

転載: blog.csdn.net/m0_74459304/article/details/130386341