数据结构入门——单链表

这篇具有很好参考价值的文章主要介绍了数据结构入门——单链表。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

链表的定义

链表的创建

头插法创建链表

尾插法创建链表

链表的删除

在头部删除元素

在尾部删除元素

查找固定元素

在链表中插入元素

在pos位置前插入

在pos位置后插入

删除链表结点

删除pos位置的结点

删除pos后的结点

链表的销毁

写在最后


前言

前面我们学习了顺序表,顺序表访问元素直接用下标就可以,支持随机访问,随即访问固然强大,但是也会有不足之处,顺序表的插入删除元素需要移动大量的元素,倒是操作很不方便,浪费大量的时间。

接下来我们学习的链表就很好的解决了这个问题,链表中的每一个元素都有对应的地址,通过“链"建立元素之间的逻辑关系。

链表的定义

链表的节点包含存储的元素,以及指向下一个结点的指针,当然链表的元素可以是任意元素,下面仅用int类型进行介绍。

typedef struct ListNode
{
	int data;
	struct ListNode* next;
}ListNode;

 

链表的创建

头插法创建链表

头插法创建链表就是每次插入的元素都是在链表的头部进行,利用BuyNewNode(int x)函数申请一个新的结点。

在插入元素时,当时第一个元素时需*pphead = newNode,后面再有元素插入链表时只需更新新结点的next指针和更新*pphead即可。

ListNode* BuyNewNode(int x)
{
	ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
	if (newNode == NULL)
	{
		printf("malloc fail\n");
		return NULL;
	}
	newNode->data = x;
	newNode->next = NULL;
	return newNode;
}
void LSPushFront(ListNode** pphead,int x)
{
	assert(pphead);
	ListNode* newnode = BuyNewNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		newnode->next = *pphead;
		*pphead = newnode;
	}
}

尾插法创建链表

尾插法创建链表,故名起义,就是每次插入的元素都是在链表的尾部,和头插法相同的是如果插入的是第一个元素的话就将*pphead的值置为新的结点。

插入其他元素时,因为是尾插法创建链表,所以需要找到链表的最后一个结点,然后将最后一个结点的tail->next指针指向申请的新结点。

void LSPushBack(ListNode** pphead, int x)
{
	assert(pphead);
	ListNode* newNode = BuyNewNode(x);
	if ((*pphead) == NULL)
	{
		*pphead = newNode;
	}
	else
	{
		ListNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newNode;
	}
}

 

链表的删除

在头部删除元素

在链表的头部删除元素,就是每次从删除链表的头部结点。

删除时需要分类讨论,如果链表只有一个元素的话就直接free()掉*pphead即可,如果链表的元素个数大于一个时,我们需要记录链表的头结点,然后再更新头结点,最后free()掉头结点。

void LSPopFront(ListNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		ListNode* pnext = *pphead;
		*pphead = (*pphead)->next;
		free(pnext);
		pnext = NULL;
	}
}

在尾部删除元素

与头部删除结点一样,如果是只有一个元素就free()掉*pphead即可

如果不是只有一个元素的话,我们要分别找到链表的最后一个结点tail以及最后一个结点的前驱结点prev,最后free()掉tail,并将prev->next置为NULL。

void LSPopBack(ListNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		ListNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		ListNode* prev = *pphead;
		while (prev->next != tail)
		{
			prev = prev->next;
		}
		free(tail);
		tail = NULL;
		prev->next = NULL;
	}
}

 

查找固定元素

遍历链表,找到值为x的结点,找到的话返回相应结点信息,查找失败则返回NULL。

ListNode* LSFind(ListNode* phead, int x)
{
	assert(phead);
	ListNode* pcur = phead;
	while (pcur)
	{
		if (pcur->data == x)
			return pcur;
		else
			pcur = pcur->next;
	}
	return NULL;
}

在链表中插入元素

在链表中插入元素,分为前插和后插。

在pos位置前插入

在进行插入操作时,要检查pos位置,若是pos和*pphead相等就是前插,直接调用即可。

若不是,则需找到pos位置的前一个结点prev,再申请结点,最后更改指针即可。

void LSInsertFront(ListNode** pphead, ListNode* pos, int x)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		LSPushFront(pphead, x);
	}
	else
	{
		//ListNode* tail = *pphead;
		//ListNode* prev = NULL;
		//while (tail != pos)
		//{
		//	prev = tail;
		//	tail = tail->next;
		//}
		//ListNode* newnode = BuyNewNode(x);
		//newnode->next = tail;
		//prev->next = newnode;

		ListNode* prev = *pphead;
		while (prev)
		{
			if (prev->next == pos)
			{
				break;
			}
			else
			{
				prev = prev->next;
			}
		}
		ListNode* newNode = BuyNewNode(x);
		prev->next = newNode;
		newNode->next = pos;
	}
}

在pos位置后插入

与前插操作相比,后插操作要简单很多,申请新节点后吗,修改pos指针和新节点指针即可

void LSInsertBack(ListNode** pphead, ListNode* pos, int x)
{
	assert(pphead);
	assert(pos);
	ListNode* newNode = BuyNewNode(x);
	newNode->next = pos->next;
	pos->next = newNode;
}

 

删除链表结点

删除pos位置的结点

删除操作开始时先检查删除位置是不是头结点或者尾结点,如果是的话直接调用头插尾插操作即可完成。

因为是删除pos位置的结点,所以我们得找到pos位置的前一个结点prev,然后修改相应指针并释放pos

void LSErase(ListNode** pphead, ListNode* pos)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);
	if (pos == *pphead)
	{
		//头删
		LSPopFront(pphead);
	}
	else if (pos->next == NULL)
	{
		LSPopBack(pphead);
	}
	else 
	{
		//ListNode* tail = *pphead;
		//ListNode* prev = NULL;
		//while (tail != pos)
		//{
		//	prev = tail;
		//	tail = tail->next;
		//}
		//prev->next = tail->next;
		//free(tail);
		//tail = NULL;

		ListNode* prev = *pphead;
		while (prev)
		{
			if (prev->next == pos)
			{
				break;
			}
			else
			{
				prev = prev->next;
			}
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

删除pos后的结点

与删除pos位置的结点相比,删除pos后的结点就要简单很多,但是要在删除前检查pos->next不为空,然后记录pos->next指向的结点,然后更新pos->next并且释放要删除的结点

void LSEraseAfter( ListNode* pos)
{
	assert(pos);
	assert(pos->next);
	ListNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del = NULL;
}

 

链表的销毁

链表的销毁只能一个一个结点的进行销毁。利用循环迭代可完成。

void LSDestory(ListNode** pphead)
{
	//链表的销毁只能一个节点一个节点的进行销毁
	assert(pphead);
	ListNode* pcur = *pphead;
	ListNode* next = NULL;
	while (pcur)
	{
		next = pcur -> next;
		free(pcur);
		pcur = next;
	}
	free(*pphead);
	free(next);
}

​​​​​​​ 

写在最后

单链表的操作是有点繁杂,但是经过后续的练习,每个小伙伴都可以掌握,后面我们继续努力!!文章来源地址https://www.toymoban.com/news/detail-831126.html

到了这里,关于数据结构入门——单链表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 单链表(数据结构)(C语言)

    这里特指无哨兵位单向非循环链表 目录 背景 概念 单链表的实现 前景提示 单链表的结构体定义 单链表的打印 关于为什么不断言phead 关于单链表的逻辑结构和物理结构 单链表的尾插 关于为什么要用到二级指针 关于尾插的本质 关于找尾整个过程的解释 关于为什么打印单链表

    2023年04月22日
    浏览(77)
  • C语言:数据结构(单链表)

    概念:链表是一种 物理存储结构上非连续 、非顺序的存储结构,数据元素的 逻辑顺序 是通过链表的 指针链接 次序实现的。 链表的结构跟火车车厢相似,淡季时车次的车厢会相应减少,旺季时车次的车厢会额外增加几节。只需要将火车里的某节车厢去掉/加上,不会影响其

    2024年04月26日
    浏览(39)
  • 【C语言】数据结构-单链表

    主页:114514的代码大冒险 qq:2188956112(欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ ) Gitee:庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com 文章目录 目录 文章目录 前言(链表的优势) 一、单链表是什么 二、单链表操作的具体代码实现 1.准备工作 2.打印链表 2.尾插(在链表末端添加数据) 3、头插(

    2024年02月02日
    浏览(46)
  • 单链表——“数据结构与算法”

    各位CSDN的uu们你们好呀,今天,小雅兰的内容终于是我们心心念念的单链表啦,这一块呢,是一个很重要的部分,也是一个对目前的我来说,比较困难的部分,下面,就让我们进入单链表的世界吧 之前小雅兰写过顺序表的内容: 顺序表(更新版)——“数据结构与算法”_认

    2023年04月26日
    浏览(44)
  • 单链表—C语言实现数据结构

    本期带大家一起用C语言实现单链表🌈🌈🌈 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的;简单来说,线性表的链式存储结构生成的表,称作“链表”。 每个元素本身由两部分组成: 1、本身的信息,称为

    2024年02月07日
    浏览(83)
  • 【算法基础】(二)数据结构 --- 单链表

    ✨个人主页:bit me ✨当前专栏:算法基础 🔥专栏简介:该专栏主要更新一些基础算法题,有参加蓝桥杯等算法题竞赛或者正在刷题的铁汁们可以关注一下,互相监督打卡学习 🌹 🌹 🌹 实现一个单链表,链表初始为空,支持三种操作: 向链表头插入一个数; 删除第 k 个插

    2023年04月17日
    浏览(97)
  • 数据结构入门 — 链表详解_单链表

    数据结构入门 — 单链表详解 * 博客主页链接:https://blog.csdn.net/m0_74014525 关注博主,后期持续更新系列文章 文章末尾有源码 *****感谢观看,希望对你有所帮助***** 第一篇:数据结构入门 — 链表详解_单链表 第二篇:数据结构入门 — 链表详解_双向链表 第三篇:数据结构入门

    2024年02月11日
    浏览(55)
  • 数据结构入门指南:单链表(附源码)

    目录 前言 尾删 头删 查找 位置前插入  位置后插入  位置删除  位置后删除  链表销毁 总结         前边关于链表的基础如果已经理解透彻,那么接下来就是对链表各功能的实现,同时也希望大家能把这部分内容熟练于心,这部分内容对有关链表部分的刷题很有帮助。废话

    2024年02月14日
    浏览(60)
  • C语言:数据结构之单链表(四)

    本篇谈一谈单链表的 改 ,具体操作就是找到他,然后修改元素即可,上一篇有相关代码,可以参考。 改函数代码如下: main函数如下:(修改第6,8,3位) 结果如下:   至此,单链表的增删改查就谈完了,只需理解它的本质是干什么,代码就很好写了。 总结:①改比较简单,

    2024年02月16日
    浏览(43)
  • C语言:数据结构之单链表(二)

    上一篇随笔谈了谈单链表是什么东西,然后进行了初始化,这篇随笔就开始对其进行操作了,首先是增,删,改,查的增。 增,顾名思义就是要增加新的元素,单链表是链式的,那就要考虑怎么去加新元素,有三种,从头部添加,从尾部添加,从中间添加。先说说从尾部添加

    2024年02月12日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包