当前位置: 首页 > article >正文

【C语言零基础入门篇 - 15】:单链表

文章目录

  • 单链表
  • 链表的基本概念
    • 单链表功能的实现
      • 单链表的初始化
      • 单链表新结点的创建
      • 单链表头插法
      • 单链表的输出
      • 单链表的查找
      • 单链表修改
      • 单链表的删除
      • 单链表所有数据结点释放
      • 源代码

单链表


链表的基本概念

一、什么是链表?
链表是数据结构中线性表的一种,其中的每个元素实际上是一个单独的结构体对象,而所有对象都通过每个元素中的指针链接在一起。

什么是结点:链表中每个结构体对象叫做结点。

什么是首元结点:其中第一个数据结点。

什么是头结点:如果第一个结点不用于存储数据,只用于代表链表的起始点,则这个结点称为链表的头结点。
在这里插入图片描述
二、单链表的特点

1、单链表没有固定的长度,可以自由增加节点。

2、单链表能够实现快速的插入删除数据。

3、与数组类似,单链表也是一种线性数据结构。

4、单链表的尾结点的后继必定指向空。

单链表和数组的区别:数组是顺序存储的,而单链表是链式存储的。

链表的结构示意图:
在这里插入图片描述

单链表功能的实现

链表的基本操作:增、删、改、查。
单链表节点的插入和删除结构示意图:
在这里插入图片描述

单链表的初始化

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

单链表新结点的创建

在这里插入图片描述

单链表头插法

在这里插入图片描述

在这里插入图片描述

单链表的输出

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

单链表的查找

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

单链表修改

在这里插入图片描述
在这里插入图片描述

单链表的删除

在这里插入图片描述
在这里插入图片描述

  • 单链表删除结点的补充:
    在这里插入图片描述

单链表所有数据结点释放

在这里插入图片描述
在这里插入图片描述

源代码

#include<stdio.h>
#include<stdlib.h>
#define TYPE int //数据类型通过定义宏的形式来进行灵活运用
#define PRINT(a) printf("%d-->", a)
#define PRINTINDEX(b, c) printf("元素值是%d\t 位置是%d\n\n", b,c)
//结点的类型 声明结点的类型
struct NODE
{
	int data; //数据域
	struct NODE*next; //指针域保存下一个结点的地址 struct NODE*
	//next是一个成员
};

//头结点类型 链表结构
struct List
{
	int len; //保存单链表中的结点个数(不包括头结点)
	struct NODE*front; //头指针 指向首元结点
	struct NODE*back; //尾指针 指向尾结点
};

//创建单链表结构 从堆区来申请内存 把首地址返回给list
struct List*initList()
{
	//申请单链表结构内存
	struct List*temp = (struct List*)malloc(sizeof(struct List));
	//初始化单链表结构的成员
	temp->len = 0;
	temp->front = NULL;
	temp->back = NULL;
	return temp;
}

//单链表结点的创建
struct NODE*CreateNode(TYPE data)
{
	struct NODE*temp = (struct NODE*)malloc(sizeof(struct NODE));
	temp->data = data; //把数据放进新结点
	temp->next = NULL; //防止野指针的出现
	return temp;
}

//单链表结点的插入 头插法
void insertHead(struct List*head, TYPE data) //list表示要增加数据的单链表
{
	//1、作为第一个数据结点插入单链表中  头指针与尾指针都需要改变指向
	if (head->front == NULL) //或者head->len == 0
	{
		//1、要生成一个新的结点
		//2、让头指针和尾指针都指向这个新结点
		head->front = head->back = CreateNode(data);
		head->len++;//单链表结点的数量+1
	}
	else//不是第一个数据结点 只需改变头指针的指向
	{
		//生成一个新的结点
		struct NODE*S = CreateNode(data);
		//新结点S指针域保存原来的首元结点的地址
		S->next = head->front;
		//更新头指针,指向新结点S
		head->front = S;
		head->len++; //单链表结点的数量+1
	}
}

//输出单链表中所有的数据
void print(struct List*head)
{
	struct NODE*p = head->front;
	while (p != NULL)
	{
		PRINT(p->data); //输出p指向的结点里面的数据
		p = p->next; //p指向下一个结点
		//p++;不能使用,单链表的物理内存不连续
	}
	printf("\n\n");
}

//单链表元素的查找 根据指定值来查找元素,并且输出元素的位置
void find(struct List*head, int val) //head=list val表示要查找的数据
{
	struct NODE*p = head->front;//p指向首元结点
	int index = 0; //index表示指定元素的位置
	while (p != NULL)
	{
		index++;
		if (p->data == val)
		{
			PRINTINDEX(p->data, index);//输出元素值和位置
		}
		p = p->next; //p指向下一个结点
	}
}

//单链表元素的修改 根据指定值
void modify(struct List*head, TYPE val, TYPE data)
//val要被修改的数据 data要修改成的数据
{
	struct NODE*p = head->front; //p指向首元结点
	while (p != NULL)
	{
		if (p->data == val)
		{
			p->data = data;//修改数据
		}
		p = p->next; //p指向下一个结点
	}
}

//单链表的删除 根据指定值来删除数据
void delete(struct List*head, TYPE val) //head=list val表示要被删除的数据
{
	//1、要找到要被删除的数据
	struct NODE*p1 = head->front; //p指向首元结点
	struct NODE*p2 = NULL;
	while (p1 != NULL)
	{
		if (p1->data == val) //找到了要被删除的数据
		{
			//情况一:p1指向是首元结点,需要更新头指针的指向
			if (p1 == head->front)
			{
				head->front = p1->next; //让p1的直接后继结点成为新的首元结点
				free(p1);
				p1 = head->front; //让p1指向新的首元结点
			}
			//情况二:p1指向的是尾结点,需要更新尾指针
			else if (p1 == head->back)
			{
				p2->next = p1->next; //给尾指针的结点域置空
				head->back = p2;
				free(p1);
				p1 = NULL;
			}
			//情况三:p1指向的结点是中间结点
			else
			{
				//p2的指针域指向p1的后继结点
				p2->next = p1->next;
				//释放删除结点
				free(p1);
				//更新p1
				p1 = p2->next;
			}
		}
		else //p2指向p1的前驱节点
		{
			p2 = p1;
			p1 = p1->next;
		}
	}
}

//假设头结点也是struct node
void delete2(struct NODE*head, TYPE val) //val表示要被删除的数据
{
	struct NODE*p1 = head;
	struct NODE*p2 = head->next;
	while (p2 != NULL)
	{
		if (p2->data = val)
		{
			p1->next = p2->next;
			free(p2);
			p2->next = p1->next;
		}
		else
		{
			p1 = p1->next;
			p2 = p2->next;
		}
	}
}

//整个单链表结点的释放 释放所有的数据结点 不是释放头节点
void AllClear(struct List*head)
{
	struct NODE*p = head->front; //p指向首元结点
	while (p != NULL)
	{
		head->front = p->next;
		free(p);
		p = head->front;
	}
	head->front = head->back = NULL;//防止野指针出现
}

int main()
{
	struct List *list = NULL; //list指向单链表 通过list来管理这个单链表
	list = initList(); //调用创建单链表函数
	//插入5个数据
	for (int j = 1; j <= 5; j++)
	{
		insertHead(list, j);
	}
	print(list);
	//find(list, 4);

	//modify(list, 5, 9);
	//print(list);
	delete(list, 4);
	print(list);

	AllClear(list);
	print(list);


	return 0;
}

http://www.kler.cn/news/324778.html

相关文章:

  • 甄选范文“论应用服务器基础软件”,软考高级论文,系统架构设计师论文
  • 静态路由和默认路由(实验)
  • 海滨体育馆管理系统:SpringBoot实现技巧与案例
  • 活动在线报名小程序源码系统 自主提交表单+创建表单 带完整的安装代码包以及搭建部署教程
  • LiveGBS流媒体平台GB/T28181功能-支持电子放大拉框放大直播视频拉框放大录像视频流拉框放大电子放大
  • 小阿轩yx-Ansible部署与应用基础
  • linux semaphore信号量操作
  • 基于nodejs+vue的农产品销售管理系统
  • 如何制作小程序商城
  • NLP任务的详细原理与步骤的详细讲解
  • 算法 求最大葫芦数
  • 如何选择合适的跨境网络专线?
  • 加速 Python for 循环
  • Unity开发绘画板——02.创建项目
  • TTPoE的设计,quic协议,KCP传输协议,快速可靠的UDP
  • 另外知识与网络总结
  • AndroidManifest.xml 文件中的 package 属性不再是强制要求定义
  • 使用6条命令完成Windows和H3C VSR的IPsec对接
  • 我想自己做一个漫画网站,我需要多大的服务器
  • cocos资源分包
  • CSS 的pointer-events属性,控制元素如何响应用户指针事件
  • 怎么给邮件加密?对邮件加密的五个绝佳方法,亲测有效!保教包会哦!
  • JIT- 栈上替换(On-Stack Replacement, OSR)
  • c++入门 类和对象(中)
  • ELK-05-skywalking监控SpringCloud服务日志
  • Java 图片合成
  • 【CKA】二、节点管理-设置节点不可用
  • UDP与TCP那个传输更快
  • 【高阶数据结构】平衡二叉树(AVL)的插入(4种旋转方法+精美图解+完整代码)
  • 深度解析:Debian 与 Ubuntu 常用命令的区别与联系