初探C语言链表(一)

2023-11-01

什么是链表???

链表是由一系列节点组成,每个节点包含两个域,一个是数据域,一个是节点域。数据域是用来保存用户数据,另外一个是指针域。链表在内存是非连续的。
拿到链表的第一个节点,就相当于拿到整个链表。
在这里插入图片描述
带头结点的好处就是对链表操作完成后,第一个节点永远是头结点。

一、静态链表

不带头结点的静态链表:!!!

#include<stdio.h>
#include<stdlib.h>
//不带头结点的静态链表
//链表结点类型定义
typedef struct Linknode
{
	int data;
	struct Linknode *next;
}Linknode;
void text()
{
	Linknode node1 = { 10, NULL };
	Linknode node2 = { 20, NULL };
	Linknode node3 = { 30, NULL };
	Linknode node4 = { 40, NULL };
	Linknode node5 = { 50, NULL };
	node1.next = &node2;
	node2.next = &node3;
	node3.next = &node4;
	node4.next = &node5;
	//如何遍历整个链表?先设置一个指针指向头结点,然后移动指针到下一个结点
	Linknode *pcurrent=&node1;//为了让这个指针指向链表的每个结点
	while (pcurrent!=NULL)
	{
		printf("%d\n", pcurrent->data);
		pcurrent = pcurrent->next;
	}

}
int main()
{
	text();
	system("pause");
	return 0;
}

二、动态链表

初始化链表

1.尾插法建立链表

//初始化链表
struct Linknode *Init_Linklist()
{
	Linknode *header = malloc(sizeof(Linknode));//这里是创建了一个头结点,并为其分配内存空间
	header->data = 1;//这里的数据随便,因为头结点的数据是不会被使用的
	header->next = NULL;//相当于以及创建了一个空的链表
	int val = -1;
	Linknode *rear = header;//这里定义一个指向尾结点的指针方便插入后续结点
	while (true)
	{
		printf("请输入插入的数据:\n");
		scanf_s("%d", &val);
		if (val == -1)
			break;
		//先创建新结点
		Linknode *newnode = malloc(sizeof(Linknode));
		//这里创建新结点和静态链表不同的地方在于结构体指针指向,我自己是这么理解的
		newnode->data = val;
		newnode->next = NULL;
		rear->next = newnode;//在尾部插入结点
		rear = newnode;//更新尾部结点
	}
	return header;
}

2.头插法建立链表

!!!之所以叫头插法是因为每次插入的结点都跟在头结点的后面,L就相当于头结点

如果要插入1,2,3,4,5那么使用头插法插入后的顺序就如图所示:
在这里插入图片描述

void Create_Linklist(Linknode *header,int a[],int n)
{
	//头插法创建链表
	//核心代码
	struct Linknode *header = malloc(sizeof(Linknode));
	struct Linknode *p;
	header->next = NULL;
	for (int i = 0; i < n; i++)
	{
		struct Linknode *p = malloc(sizeof(Linknode));
		p->data = a[i];
		p->data = header->next;
		header->next = p;
	}

}

三、动态链表的基本操作

1.遍历

//遍历结点
void print_Linklist(Linknode *header)
{
	Linknode *pcurrent = header->next;
	if (header == NULL)
		return;
	while (pcurrent != NULL)
	{
		printf("%d\n", pcurrent->data);
		pcurrent = pcurrent->next;//让定义的结点指向要打印的结点
	}
}

2.查找

struct Linknode* Find_Linklist(header)
{
	struct Linknode *pRev = header;
	struct Linknode *pCurrent = pRev->next;//指向当前位置的结点
	while (pCurrent!=NULL)
	{
		if (pCurrent->data == old)
			break;
		pRev = pCurrent;
		pCurrent = pCurrent->next;
	}
	if (pCurrent == NULL)//如果pCurrent为空,说明根本就没有找到old
	{
		return;
	}
	return pCurrent;
}

3.插入

需要用两个指针,一个pRev指向前一个结点,一个pCurrent指向要插入位置的结点
在这里插入图片描述
!!!在这里一定要先连接路线1,在连接路线2,。因为如果先连接路线2那么pCurrent结点的地址就会丢失

核心代码:

newnode->next=pRev->next;
pRev->next=newnode;
//在链表中值为old的后面插入数据new
void Insert_Linklist(Linknode *header, int old, int new)
{
	if (header == NULL)//先判断一下是不是空链表
		return;
	//定义两个辅助指针变量
	struct Linknode *pRev = header;
	struct Linknode *pCurrent = pRev->next;//指向当前位置的结点
	while (pCurrent!=NULL)
	{
		if (pCurrent->data == old)
			break;
		pRev = pCurrent;
		pCurrent = pCurrent->next;
	}
	if (pCurrent == NULL)//如果pCurrent为空,说明根本就没有找到old
	{
		return;
	}
	//如果没有找到数据,把新结点插入到尾部就不要上述if语句的内容即可
	//先创建新结点
	struct Linknode *newnode = malloc(sizeof(Linknode));
	newnode->data = new;
	newnode->next = NULL;
	//新结点插入链表
	newnode->next = pRev->next;
	pRev->next = newnode;
}

4.清空

清空链表的意思就是链表只剩一个头结点!!!

void Remove_Linklist(Linknode *header, int val)
{
	if (header == NULL)
		return;
	//辅助指针变量
	struct Linknode *pCurrent = header->next;
	while (pCurrent->next != NULL)
	{
		//先保存一下当前结点的下一个结点地址
		struct Linknode *pnext = pCurrent->next;
		//释放当前结点的内存
		free(pCurrent);
		//pCurrent指向下一结点
		pCurrent = pnext;
	}
	header->next = NULL;
}

5.删除

删除值为val的结点,就是把值为val结点的前驱结点和后继节点连接起来。

//删除值为val的结点
void Remove_Linklist(Linknode *header, int val)
{
	if (header == NULL)
		return;
	struct Linknode *pRev = header;
	struct Linknode *pCurrent =pRev->next;
	//!!!如果pCurrent为空的话说明没有找到,返回即可
	while (pCurrent != NULL)
	{
		if (pCurrent->data == val)
			break;
		pRev = pCurrent;
		pCurrent = pCurrent->next;
	}
	if (pCurrent == NULL)
		return;
	pRev->next = pCurrent->next;
	free(pCurrent);
}

6.销毁

void Destory_Linklist(Linknode *header)
{
	struct Linknode *pCurrent = header->next;
	while (pCurrent != NULL)
	{
		//先保存一下当前结点的下一个结点地址
		struct Linknode *pnext = pCurrent->next;
		//释放当前结点的内存
		printf("%d该节点被销毁\n", pCurrent->data);
		free(pCurrent);
		//指针向后推移
		pCurrent = pnext;
	}
}

四、链表的综合应用


#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
//不带头结点的静态链表
//链表结点类型定义
typedef struct Linknode
{
	int data;
	struct Linknode *next;
}Linknode;
//初始化链表
struct Linknode *Init_Linklist()
{
	Linknode *header = malloc(sizeof(Linknode));//这里是创建了一个头结点,并为其分配内存空间
	header->data = 1;//这里的数据随便,因为头结点的数据是不会被使用的
	header->next = NULL;//相当于以及创建了一个空的链表
	int val = -1;
	Linknode *rear = header;//这里定义一个指向尾结点的指针方便插入后续结点
	while (true)
	{
		printf("请输入插入的数据:\n");
		scanf_s("%d", &val);
		if (val == -1)
			break;
		//先创建新结点
		Linknode *newnode = malloc(sizeof(Linknode));
		//这里创建新结点和静态链表不同的地方在于结构体指针指向,我自己是这么理解的
		newnode->data = val;
		newnode->next = NULL;
		rear->next = newnode;//在尾部插入结点
		rear = newnode;//更新尾部结点
	}
	return header;
}
//在链表中值为old的后面插入数据new
void Insert_Linklist(Linknode *header, int old, int new)
{
	if (header == NULL)//先判断一下是不是空链表
		return;
	//定义两个辅助指针变量
	struct Linknode *pRev = header;
	struct Linknode *pCurrent = pRev->next;//指向当前位置的结点
	while (pCurrent!=NULL)
	{
		if (pCurrent->data == old)
			break;
		pRev = pCurrent;
		pCurrent = pCurrent->next;
	}
	//if (pCurrent == NULL)//如果pCurrent为空,说明根本就没有找到old
	//{
	//	return;
	//}
	//先创建新结点
	struct Linknode *newnode = malloc(sizeof(Linknode));
	newnode->data = new;
	newnode->next = NULL;
	//新结点插入链表
	newnode->next = pRev->next;
	pRev->next = newnode;
}
//删除值为val的结点
void Remove_Linklist(Linknode *header, int val)
{
	if (header == NULL)
		return;
	struct Linknode *pRev = header;
	struct Linknode *pCurrent =pRev->next;
	//!!!如果pCurrent为空的话说明没有找到,返回即可
	while (pCurrent != NULL)
	{
		if (pCurrent->data == val)
			break;
		pRev = pCurrent;
		pCurrent = pCurrent->next;
	}
	if (pCurrent == NULL)
		return;
	pRev->next = pCurrent->next;
	free(pCurrent);
}
//遍历结点
void print_Linklist(Linknode *header)
{
	Linknode *pcurrent = header->next;
	if (header == NULL)
		return;
	while (pcurrent != NULL)
	{
		printf("%d\n", pcurrent->data);
		pcurrent = pcurrent->next;
	}
}
//销毁链表
void Destory_Linklist(Linknode *header)
{
	struct Linknode *pCurrent = header->next;
	while (pCurrent != NULL)
	{
		//先保存一下当前结点的下一个结点地址
		struct Linknode *pnext = pCurrent->next;
		//释放当前结点的内存
		printf("%d该节点被销毁\n", pCurrent->data);
		free(pCurrent);
		//指针向后推移
		pCurrent = pnext;
	}
}
//清空链表
void Clear_Linklist(Linknode *header)
{
	if (header == NULL)
		return;
	//辅助指针变量
	struct Linknode *pCurrent = header->next;
	while (pCurrent->next != NULL)
	{
		//先保存一下当前结点的下一个结点地址
		struct Linknode *pnext = pCurrent->next;
		//释放当前结点的内存
		free(pCurrent);
		//pCurrent指向下一结点
		pCurrent = pnext;
	}
	header->next = NULL;
}
int main()
{
	//初始化链表 100 200 666 300 400 500 600
	Linknode *header = Init_Linklist();
	//打印链表
	print_Linklist(header);
	printf("-----------------------------\n");
	//插入数据
	Insert_Linklist(header, 1000, 666);
	print_Linklist(header);
	printf("-----------------------------\n");
	//清空链表
	Clear_Linklist(header);
	print_Linklist(header);
	Insert_Linklist(header, 1000, 111);
	Insert_Linklist(header, 1000, 211);
	Insert_Linklist(header, 1000, 311);
	Insert_Linklist(header, 1000, 411);
	print_Linklist(header);
	printf("-----------------------------\n");
	Remove_Linklist(header, 311);
	print_Linklist(header);
	system("pause");
	return 0;
}

初级链表的学习到这里就结束了,接下来还会深入学习链表会更新双向链表,循环链表等知识!!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

初探C语言链表(一) 的相关文章

  • 不同jdk环境导致md5不一致

    加密访问接口 运行jar包发现就导致错误 idea测试没有问题 这还都是在本机运行 单步调试发现出现结果不一致地方出现在以下代码处 MessageDigest sec MessageDigest getInstance MD5 sec re
  • 部门来了个拿25k出来的00后测试卷王,老油条表示真干不过,已被...

    内卷的来源 内卷最早的 出处 是几张名校学霸的图片 大学生们刷爆朋友圈的几张 内卷 图片是这样的 有的人骑在自行车上看书 有的人宿舍床上铺满了一摞摞的书 有的人甚至边骑车边端着电脑写论文 这些图片最早在清华北大的学霸之间流传 之后 边骑车边
  • Linux共享文件夹到windows服务器

    1 安装Samba yum y install samba samba client samba common 2 添加要使用的账号 useradd s sbin nologin username smbpasswd a username
  • 闭眼推荐,9 个不能错过的机器学习数据集

    内容一览 本期整理了 HyperAI超神经官网近期更新的 9 个数据集 涉及人脸识别 姿态估计 自动驾驶三个领域 关键词 人脸识别 姿态估计 自动驾驶 本文首发自微信公众号 HyperAI 超神经 近期 HyperAI超神经官网更新了 30
  • springboot + vue项目本地化部署配置内+外网

    1 项目使用nginx做访问代理 配置如下 内网访问配置 server listen 80 server name 192 168 0 235 client max body size 100M charset koi8 r access

随机推荐

  • 开发Hololens遇到The type or namespace name ‘HandMeshVertex‘ could not be found..

    The type or namespace name HandMeshVertex could not be found are you missing a using directive or an assembly reference
  • C语言——循环控制语句

    文章目录 循环控制语句 for循环控制 1 基本语法 2 注意事项和细节说明 3 练习 1 打印1 100之间所有是9的倍数的整数的个数及总和 使用for完成 2 先死后活的一种编程思想 while循环控制 1 基本语法 2 注意事项和细节
  • 谷歌浏览器如何安装vue调试工具

    下载vue devtools压缩包 git地址 vue devtools 安装环境 将下载的压缩包解压 并通过命令行进入vue devtools master文件夹中 输入安装命令 cnpm install进行安装 编译 输入编译命令 np
  • a-textarea实现自动出现滚动条不能自动伸缩

    deep textarea width 100 height 50px overflow y auto resize none
  • 2023年贵州省职业技能大赛“网络安全” 项目比赛任务书

    2023年贵州省职业技能大赛 网络安全 项目比赛任务书 2023年贵州省职业技能大赛 网络安全 项目比赛任务书 A模块基础设施设置 安全加固 200分 A 1 登录安全加固 Windows Linux A 2 Nginx安全策略 Linux
  • MYSQL数据文件默认在哪个目录下?

    原文地址 MYSQL数据文件默认在哪个目录下 在Windows平台默认一般在C ProgramData MySQL C ProgramData MySQL MySQL Server X X Data文件夹中 无论在Windows还是在Lin
  • STM32 (三)GPIO的八种模式及其原理

    一 GPIO简介 GPIO就是通用I O 输入 输出 端口 是STM32可控制的引脚 STM32芯片的GPIO引脚与外部设备连接起来 可实现与外部通讯 控制外部硬件或者采集外部硬件数据的功能 二 GPIO工作模式 1 四种输入模式 GPIO
  • 每天一个linux命令(46):vmstat命令

    vmstat是Virtual Meomory Statistics 虚拟内存统计 的缩写 可对操作系统的虚拟内存 进程 CPU活动进行监控 他是对系统的整体情况进行统计 不足之处是无法对某个进程进行深入分析 vmstat 工具提供了一种低开
  • 用C++做高级病毒

    今天教大家做几个超级厉害的病毒 看完这篇文章之后你就能成为一名高级黑客了 声明 若电脑收到损伤 作者一律不负责 1 鼠标病毒 作用 让鼠标一直停在一个地方动不了 include
  • js Dom事件

    1 onclick 点击事件 2 ondbclick 双击事件 3 onmousedown 鼠标按下事件 4 onmouseup 鼠标松开事件 5 onmouseenter 鼠标移入事件 不支持冒泡 只触发一次 6 onmouseover
  • xml实体小实例

    如何定义和使用实体 一下是实体的一个小实例 gt
  • C++里仿函数是什么

    一 什么是仿函数 仿函数的意思是 它不是函数 其实是个类 但用法和函数一样 既然是个类 就可以存储很多变量和其他的信息 然后实现纯函数实现不了的功能 所以在一些需要函数作为参数的地方可以用仿函数代替 在STL里很多地方用到了仿函数 二 仿函
  • Java 密码复杂度校验

    1 需求 复杂性 用户的密码中必须包含的字符类型 默认为中 弱 必须包含小写字母 中 必须包含小写字母 数字 强 必须包含小写字母 数字 大写字母 特殊字符 鼠标移入的提示文字相同 注 检查密码复杂度 仅新增账户 重置密码时生效 已有账户密
  • 揭示OLED透明屏数据:探索未来显示技术的潜力

    OLED透明屏作为一项颇具吸引力的显示技术 以其独特的特点和卓越的画质在市场上引起了广泛关注 在这篇文章中 尼伽将和大家一起深入探索OLED透明屏的数据 通过具体的市场趋势分析 技术指标解析 应用领域探讨和未来前景展望 为读者提供全面了解和
  • wish虚拟服务器,云服务器操作wish

    云服务器操作wish 内容精选 换一换 按需计费 按需计费是后付费模式 按弹性云服务器的实际使用时长计费 可以随时开通 删除弹性云服务器 包年 包月 包年 包月是预付费模式 按订单的购买周期计费 适用于可预估资源使用周期的场景 价格比按需计
  • [开发

    ModelMapper是一个用于对象之间转换的Java库 它能够自动映射一个Java对象的属性到另一个Java对象 依赖安装
  • C/C++

    文章目录 空间的读写 作用 实现strlen 实现strcpy 非字符空间 void 返回值 返回连续空间类型 示例 函数内部实现 示例 参考 麦子学院 嵌入式C语言高级 C语言函数的使用 空间的读写 void fun char p con
  • VUE enement-ui之table表格隐藏滚动条

    只需修改样式即可 deep el table body wrapper webkit scrollbar width 0 注意 element ui表格很多样式修改都需要加深度穿透才能生效 效果图
  • 深度神经网络的matlab实现,深度神经网络代码matlab

    为什么不用matlab做深度学习 matlab可以做深度学习 但是从实用性的角度来讲matlab的实现效率相对较低 训练耗时较长 初次学习计算机语言就选择matlab不是一个明智的选择 最好选用C或者Basic作为入门语言 matlab是一
  • 初探C语言链表(一)

    初探链表 一 静态链表 二 动态链表 初始化链表 1 尾插法建立链表 2 头插法建立链表 三 动态链表的基本操作 1 遍历 2 查找 3 插入 4 清空 5 删除 6 销毁 四 链表的综合应用 什么是链表 链表是由一系列节点组成 每个节点包