猿创征文 | 单链表的创建和删除(详解+图解)

1.收获

进一步理解动态内存,指针,和结构体

2. 什么是单链表?

在数据结构中,存储结构有一种是链式存储结构。单链表就是链式存储的一种实现方式。

​​ ​​它与顺序结构存储不同,顺序结构在内存中开辟的空间一定是连续的,例如我们的数组就是顺序存储。

单链表中每个节点(矩形)在内存中的地址不是连续的,通过指针来找到下一个节点。
每一个节点中存放两个内容,一个是数据,一个是指针。指针是用来找到下一个节点。
也就是说,下一个节点,只能通过它上一个节点去访问它。

这里介绍单链表的头插入和头删除

这里讲的动态内存函数是malloc和free
简单介绍一下这两个函数。
malloc()
向堆区申请一块空间,返回值是地址,地址的类型是void*因此在接收这个地址的时候,需要强制类型转换。
()内部是你需要申请多大的空间单位是字节。
一般可以这样malloc( sizeof( 类型 )*常数 )使用 。
int * p = (int * ) malloc ( sizeof(int) * 10);
free()
释放在堆区开辟的空间,即释放malloc,realloc,calloc开辟的空间
()内部是 要释放空间的起始地址。

3.节点的创建

typedef struct Node
{
	int data;//存数据
	struct Node* next;//指向下一个节点(存地址)
}Node_t;//将类型 struct Node 重命名为 Node_t

这里要注意的是,typedef重命名结构体类型名,修改后名字的位置在’ ; '的前面,即Node_t == struct Node

4.主函数的实现

int main()
{
	//头节点
	Node_t* head = AollocNode(0);
	//该函数用来申请空间,和存数据
	int i = 0;
	printf("头插入...\n");
	for (i = 1; i < 10; i++)
	{
		//插入节点
		//我们需要知道地址才能插入,所以要传入头节点。
		//i 表示我们插入的数据。
		HeadInsertNode(head, i);
		//展示插入的效果
		ShowNode(head);
	}
	printf("头删除...\n");
	for (i = 1; i < 10; i++)
	{
		//同样的我们要删除节点需要知道位置
		HeadDeleteNode(head);
		//展示删除的效果
		ShowNode(head);
	}
	
	//堆区申请的空间需要释放回去
	//避免内存泄露
	
	free(head);
	
	//避免野指针,将指针置为NULL
	head = NULL;
	return 0;
}

头节点就相当于火车头,其他节点相当于车厢。头节点是链表的起始部位,(给你一个地址)要通过头节点才能对单链表进行操作。

5.子函数的实现

5.1 AollocNode的实现

功能:在堆区开辟空间,存储数据(赋值)
在初始化的时候一般默认下一个节点指向NULL(避免野指针)

Node_t* AollocNode(int x)
{
	Node_t* newnode = (Node_t*)malloc(sizeof(Node_t));
	newnode->data = x;//存数据
	newnode->next = NULL;//指向下一个节点(最后一个节点指向NULL)
	return newnode;
}

5.2 HeadInsertNode的实现

如何做到头插入?一定是改变指针的指向来实现的,看图理解。

第一次头插入

第二次头插入

第三次头插入

看了这三张图,相信你一定有所发现。头插入,是通过头节点和新节点的指向来达到能够连续访问节点的目的。
我们来看代码:

void HeadInsertNode(Node_t* head, int x)
{
	Node_t* new = AollocNode(x);//新增节点,x为存储的数据。
	new->next = head->next;
	head->next = new;
}

5.3 ShowNode的实现

功能:打印节点中存放的数据。

ShowNode(Node_t* head)
{
	Node_t* p = head->next;//指向第一节点
	while (p)//直到指向NULL循环结束
	{
		printf("%d->", p->data);//打印数据
		
		Sleep(1000);
		//停屏1s 看打印效果 图片看不出打印效果,可以自行尝试,更加理解头插入是什么样的。
		
		p = p->next;//指向下一个节点
	}
	printf("NULL\n"); //为了更了解单链表的样子才如此设计。
}

运行结果:

5.4 HeadDeleteNode的实现

这个头删除是最简单的。只要将头节点指向的第一个节点释放,并且头节点指向第二个节点,就完成了删除。

为什么可以这么做呢?我们使用的是内存管理的函数,开辟的空间,是可以free。释放之后就把原有所属的空间归还给操作系统了。

我们来看看图。

假设插入三次。

先看原图

第一次头删除

第二次头删除

第三次头删除

void HeadDeleteNode(Node_t* head)
{
	Node_t* p = head->next;
	//新增指针p指向头节点指向的第一个节点

	head->next = p->next;
	//改变头节点的指向,指向第一个节点的下一个节点
	//即头节点指向第二个节点

	free(p);
	//p已经指向了第一个节点的起始地址,free(p)就是释放第一个节点
}

运行结果:

在这里插入图片描述

6.源代码

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
typedef struct Node
{
	int data;
	struct Node* next;
}Node_t;//将类型 struct Node 重命名为 Node_t

//向堆区开辟空间给节点,并赋值
Node_t* AollocNode(int x)
{
	Node_t* newnode = (Node_t*)malloc(sizeof(Node_t));
	newnode->data = x;//存数据
	newnode->next = NULL;//指向下一个节点(最后一个节点指向NULL)
	return newnode;
}
void HeadInsertNode(Node_t* head, int x)
{
	Node_t* new = AollocNode(x);//新增节点,x为存储的数据。
	new->next = head->next;
	head->next = new;
}
ShowNode(Node_t* head)
{
	Node_t* p = head->next;
	while (p)
	{
		printf("%d->", p->data);
		Sleep(100);
		p = p->next;
	}
	printf("NULL\n");
}
void HeadDeleteNode(Node_t* head)
{
	Node_t* p = head->next;//新增指针p指向头节点指向的第一个节点

	head->next = p->next;
	//改变头节点的指向,指向第一个节点的下一个节点
	//即头节点指向第二个节点

	free(p);
	//p已经指向了第一个节点的起始地址,free(p)就是释放第一个节点
}
int main()
{
	//头节点(第一个节点)
	Node_t* head = AollocNode(0);//
	int i = 0;
	printf("头插入...\n");
	for (i = 1; i < 10; i++)
	{
		//插入节点
		//我们需要知道地址才能插入,所以要传头节点。
		//i 表示我们插入的数据。
		HeadInsertNode(head, i);
		//展示插入的效果
		ShowNode(head);
	}
	printf("头删除...\n");
	for (i = 1; i < 10; i++)
	{
		//同样的我们要删除节点需要知道位置
		HeadDeleteNode(head);
		//展示插入的效果
		ShowNode(head);
	}
	//堆区申请的空间需要释放回去
	//避免内存泄露
	free(head);
	//避免野指针,将指针置为NULL
	head = NULL;
	return 0;
}

7.结束语

可以自己尝试去写写,图片也自己画画,加深印象。
希望对你有所帮助。
理解了可以进阶下一篇博客。
单链表的操作(基本操作和一些复杂操作)

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值