[C语言][数据结构][链表] 单链表的从零实现!

news/2025/2/22 15:01:03

目录

零.必备知识

1.一级指针 && 二级指针

2. 节点的成员列表

    a.数据

    b.指向下一个节点的指针.

3. 动态内存空间的开辟 (malloc-calloc-realloc)

一.单链表的实现与销毁 

        1.1 节点的定义

        1.2 单链表的尾插

        1.3 单链表的头插

        1.4 单链表的尾删

        1.5 单链表的头删 

        1.6 单链表的查找

        1.7 在指定位置之前插入数据

        1.8 在指定位置之后插入数据

        1.9 删除指定位置的数据

        1.10 删除指定位置之后的数据

        1.11 销毁单链表 

二. 单链表源码

SingleList.h

SingleList.c 


零.必备知识

1.一级指针 && 二级指针

2. 节点的成员列表

    a.数据

    b.指向下一个节点的指针.

3. 动态内存空间的开辟 (malloc-calloc-realloc)


一.单链表的实现与销毁 

注:具体解释都在代码的注释中!(在代码中具体分析)

        1.1 节点的定义

        1.2 单链表的尾插

 

        1.3 单链表的头插

 

        1.4 单链表的尾删

        1.5 单链表的头删 

        1.6 单链表的查找

        1.7 在指定位置之前插入数据

        1.8 在指定位置之后插入数据

        

 

        1.9 删除指定位置的数据

        1.10 删除指定位置之后的数据

        1.11 销毁单链表 

二. 单链表源码

SingleList.h

#define  _CRT_SECURE_NO_WARNINGS
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

// 节点的定义
typedef int SLTDateType;
typedef struct SingleListNode
{
	SLTDateType date;
	struct SingleListNode* next;
}SLTNode;

// 单链表的展示
void SLTPrint(SLTNode* phead);
// 单链表的尾插
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);
// 在指定位置之前插入数据
void SLTInsertBefore(SLTNode** pphead, SLTNode* pos, SLTDateType x);
// 在指定位置之后插入数据
void SLTInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDateType x);
// 删除指定位置的数据
void SLTErase(SLTNode** pphead, SLTNode* pos);
// 删除指定位置之后的数据
void SLTEraseAfter(SLTNode** pphead, SLTNode* pos);
// 销毁单链表
void SLTDestroy(SLTNode** pphead);

SingleList.c 

#define  _CRT_SECURE_NO_WARNINGS
#include "SingleList.h"
// 单链表的展示
void SLTPrint(SLTNode* phead)
{
	SLTNode* pcur = phead; //current 当前的,现在的  currect 正确的
	while (pcur != NULL) {
		printf("%d->", pcur->date);
		pcur = pcur->next;
	}
	printf("NULL\n");
}
// 节点的创造
SLTNode* SLTCreat(SLTDateType x)
{
	SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newNode == NULL) {
		printf("创建失败!\n");
		exit(1);
	}
	newNode->date = x;
	newNode->next = NULL;
	return newNode;
}
// 单链表的尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x)
{
	assert(pphead);
	// 创建节点
	SLTNode* newNode = SLTCreat(x);
	// 没有节点
	if ((*pphead) == NULL) {
		(*pphead) = newNode;
	}
	else { // 有一个或多个节点
		SLTNode* pcur = (*pphead);
		while (pcur->next != NULL) {
			pcur = pcur->next;
		}
		pcur->next = newNode;
	}
}
// 单链表的头插
void SLTPushFront(SLTNode** pphead, SLTDateType x)
{
	assert(pphead);
	SLTNode* pcur = (*pphead);
	// 创建节点
	SLTNode* newNode = SLTCreat(x);
	// 没有节点
	if ((*pphead) == NULL) {
		(*pphead) = newNode;
	}
	else { // 有一个或者多个节点
		newNode->next = (*pphead);
		(*pphead) = newNode;
	}
}
// 单链表的尾删
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead && (*pphead));
	SLTNode* pcur = (*pphead);
	SLTNode* prev = (*pphead);
	// 只有一个节点
	if (pcur->next == NULL) {
		free(*pphead);
		(*pphead) = NULL;
		pcur = NULL;
		prev = NULL;
	}
	else { // 有多个节点
		while (pcur->next != NULL) {
			prev = pcur;
			pcur = pcur->next;
		}
		free(pcur);
		pcur = NULL;
		prev->next = NULL;
	}
}
// 单链表的头删
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && (*pphead));
	SLTNode* pcur = (*pphead);
	// 只有一个节点
	if (pcur->next == NULL) {
		free(*pphead);
		(*pphead) = NULL;
		pcur = NULL;
	}
	else { //有多个节点
		(*pphead) = (*pphead)->next;
		free(pcur);
		pcur = NULL;
	}
}
// 单链表的查找
SLTNode* SLTFind(SLTNode* phead, SLTDateType x)
{
	SLTNode* pcur = phead;
	while (pcur != NULL) {
		if (pcur->date == x) {
			printf("找到了!\n");
			return pcur;
		}
		pcur = pcur->next;
	}
	printf("找不到!\n");
	return NULL;
}
// 在指定位置之前插入数据
void SLTInsertBefore(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
	assert(pphead);
	SLTNode* pcur = (*pphead);
	// 创建节点
	SLTNode* newNode = SLTCreat(x);
	// 头插
	if (pos == (*pphead) || (*pphead) == NULL) {
		SLTPushFront(pphead, x);
	}
	else { //正常插入
		while (pcur->next != NULL) {
			if (pcur->next == pos) {
				newNode->next = pcur->next;
				pcur->next = newNode;
				break;
			}
			pcur = pcur->next;
		}
	}
}
// 在指定位置之后插入数据
void SLTInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
	assert(pphead);
	// 创建节点
	SLTNode* newNode = SLTCreat(x);
	if ((*pphead) == NULL || pos == (*pphead)) {
		// 尾插
		SLTPushBack(pphead, x);
	}
	else { //正常插入
		SLTNode* pcur = (*pphead);
		while (pcur->next != NULL) {
			if (pcur == pos) {
				newNode->next = pcur->next;
				pcur->next = newNode;
				break;
			}
			pcur = pcur->next;
		}
	}
}
// 删除指定位置的数据
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && (*pphead));
	// 处理特殊情况(头删)
	if ((*pphead) == pos) {
		SLTPopFront(pphead);
	}
	else {
		SLTNode* prev = (*pphead);
		SLTNode* pcur = (*pphead);
		while (pcur != NULL) {
			if (pcur == pos) {
				prev->next = pcur->next;
				free(pcur);
				pcur = NULL;
				prev = NULL;
				break;
			}
			prev = pcur;
			pcur = pcur->next;
		}
	}
}
// 删除指定位置之后的数据
void SLTEraseAfter(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && (*pphead));
	SLTNode* pcur = (*pphead);
	while (pcur->next != NULL) {
		if (pcur == pos) {
			SLTNode* tmp = pcur->next;
			pcur->next = pcur->next->next;
			free(tmp);
			tmp = NULL;
			break;
		}
		pcur = pcur->next;
	}
}
// 销毁单链表
void SLTDestroy(SLTNode** pphead)
{
	assert(pphead && (*pphead));
	SLTNode* pcur = (*pphead);
	SLTNode* prev = (*pphead);
	while (pcur != NULL) {
		prev = pcur;
		pcur = pcur->next;
		free(prev);
	}
	prev = NULL;
	(*pphead) = NULL;
}


http://www.niftyadmin.cn/n/5480406.html

相关文章

AD转换(模数转换)

一、AD的基本概念 AD转换是将时间连续和幅值连续的模拟量转换为时间离散、幅值也离散的数字量。使输出的数字量与输入的模拟量成正比。 AD转换的过程有四个阶段&#xff0c;即采样、保持、量化和编码。 采样是将连续时间信号变成离散时间信号的过程。经过采样&#xff0c;时间…

【Linux】环境下OpenSSH升级到 OpenSSH_9.6P1(图文教程)

漏洞描述 OpenSSH&#xff08;OpenBSD Secure Shell&#xff09;是加拿大OpenBSD计划组的一套用于安全访问远程计算机的连接工具。该工具是SSH协议的开源实现&#xff0c;支持对所有的传输进行加密&#xff0c;可有效阻止窃听、连接劫持以及其他网络级的攻击。OpenSSH 9.6之前…

arm工作模式、arm9通用寄存器、异常向量表中irq的异常向量、cpsr中的哪几位是用来设置工作模式以及r13,r14,15别名是什么?有什么作用?

ARM 首先先介绍一下ARM公司。 ARM成立于1990年11月&#xff0c;前身为Acorn计算机公司 主要设计ARM系列RISC处理器内核 授权ARM内核给生产和销售半导体的合作伙伴ARM公司不生产芯片 提供基于ARM架构的开发设计技术软件工具评估版调试工具应用软件总线架构外围设备单元等等CPU中…

迭代器模式:优雅地遍历数据集合

在软件设计中&#xff0c;迭代器模式是一种常见且有用的设计模式&#xff0c;它允许顺序访问一个聚合对象中的各个元素&#xff0c;而又不暴露该对象的内部表示。这种模式在需要对集合进行遍历操作而又不想暴露集合内部结构的场景下非常有用。 一、迭代器模式的使用条件 访问集…

【就近接入,智能DNS-Geo DNS ,大揭秘!】

做过后端服务或者网络加速的小伙伴&#xff0c;可能或多或少都听说过&#xff0c;智能DNS或者Geo DNS&#xff0c;就是根据用户的位置&#xff0c;返回离用户最近的服务节点&#xff0c;就近接入&#xff0c;以达到服务提速的效果。 那么大家有没想过&#xff0c;这个背后的原理…

vue3知识整理

vue3知识整理 1. Vue简介Vue是什么Vue版本Vue API风格创建vue项目vue目录结构 2. 模版语法 及 属性绑定文本插值原始HTMLAttribute 绑定使用 JavaScript 表达式指令 Directives​ 3. 条件渲染v-if 与 v-show 4. 列表渲染通过key管理状态 5. 事件事件处理 及 事件传参事件修饰符…

【无标题】系统思考—心智模式

“直到你使无意识变为有意识&#xff0c;它将指导你的生活并且你会称之为命运。”—卡尔荣格 心智模式深藏于我们内心之中&#xff0c;它潜移默化地影响着我们对世界的理解和判断。往往这些影响是如此隐蔽&#xff0c;以至于我们自己都未必察觉到是什么在驱动我们的选择、决策…

uniapp小程序中使用video视频播放卡顿

问题:在使用uniapp小程序的video视频播放,视频已经在播放了,但是进度条没走,还是卡顿的状态(测试ios能正常使用,安卓手机会出现此问题) 在网上找了很多方法,最多的说是用:custom-cache"false",试了并没有效果,看来和我问题不一样,后来用了个简单粗暴的方法,发现是有效…