【数据结构】单链表的实现

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

🌇个人主页:平凡的小苏

📚学习格言:别人可以拷贝我的模式,但不能拷贝我不断往前的激情

🛸C语言专栏:https://blog.csdn.net/vhhhbb/category_12174730.html

🚀数据结构专栏:https://blog.csdn.net/vhhhbb/category_12211053.html

        家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真重要,各位路过的友友麻烦多多点赞关注,欢迎你们的私信提问,感谢你们的转发!

        关注我,关注我,关注我,你们将会看到更多的优质内容!!

【数据结构】单链表的实现 

【数据结构】单链表的实现

目录

 1、单链表存储结构定义

2、单链表的优缺点

3、单链表的实现 

3.1、线性单链表的存储结构

3.2、单链表的插入

3.3、单链表的删除 

3.4、单链表打印

3.5、单链表查找

3.6、单链表的销毁

4、源码

4.1、SList.h 

4.2、SList.c

4.3、Test.c


 

 1、单链表存储结构定义

  • 线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。这就意味着,这些数据元素可以存在内存未被占用的任意位置。
  • 以前在顺序结构中,每个数据元素只需要存储数据元素信息就可以了。现在链式结构中,除了要存储数据元素信息外,还要存储它的后继元素的存储地址。
  • 因此,为了表示每个数据元素ai与其直接后继数据元素a(i+1)之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称作指针。这两部分信息组成数据元素ai的存储映像,称为结点。
  • n个结点(ai的存储映像)链结成一个链表,即为线性表(a1,a2,......,an)的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做单链表。

2、单链表的优缺点

简单的对单链表结构和顺序存储结构做对比:

存储分配方式:

        1.顺序存储结构用一段连续存储单元依次为存储线性表的数据元素

        2.单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素

时间性能:

        1.查找:顺序存储结构O(1)

                      单链表O(n)

        2.插入和删除:

                       顺序存储结构需要平均移动表长一半的元素,时间复杂度为O(n)

                       单链表在找出位置的指针后,插入和删除时间复杂度仅为O(1)]

空间性能:

        1.顺序存储结构需要预分配存储空间,分小了,易发生上溢,分大了,浪费

        2.单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制

结论:

1.若线性表需要频繁查找,很少进行插入和删除操作时,宜采用顺序存储结构。

2.当线性表中的元素个数变化较大或者根本不知道有多大时,最好使用单链表。

3、单链表的实现 

3.1、线性单链表的存储结构

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;//数据域
	struct SListNode* next;//指针域
}SListNode;

3.2、单链表的插入

SListNode* BuySListNode(SLTDateType x)//申请结点函数
{
	SListNode* new = (SListNode*)malloc(sizeof(SListNode));
	if (new == NULL)
	{
		perror("malloc fail:");
		exit(-1);
	}
	new->data = x;
	new->next = NULL;
	return new;
}
void SListInsert(SListNode** pplist, SListNode* pos, SLTDateType x)
{
	assert(pplist);
    assert(pos);
	SListNode* new = BuySListNode(x);
	SListNode* prev = *pplist;
	if (*pplist == pos)//pos处于单链表的头就是头插
	{
		new->next = *pplist;
		*pplist = new;
	}
	else
	{
		while (prev->next != pos)//处于pos的前面插入一个数
		{
			prev = prev->next;
		}
		new->next = pos;
		prev->next = new;
	}
}

算法思路:

(1)声明——指针pplist指向链表头;

(2)当prev->next不等于pos时,让p的指针向后移动,不断指向下一结点;

(3)pos不等于空就代表这个结点存在,若不存在就断言;

(4)单链表插入的标准语句new-> = pos; prev->next = new;

注:

在这段算法代码中,我们用到了c语言的malloc标准函数,它的作用就是生成一个新的结点,其类型与Node是一样的,其实质就是在内存中找了一小块空地,准备用来存放数据。

3.3、单链表的删除 

        现在我们来看看单链表的删除,设存储元素data的结点为pos,要实现将结点pos删除单链表的操作,其实就是将他的前继结点的指针绕过,指向它的后继结点即可。

实现代码如下:

void SListErase(SListNode** pplist, SListNode* pos)
{
	assert(pplist);
	assert(*pplist);
	assert(pos);
	SListNode* prev = *pplist;
	SListNode* cur = *pplist;
	while (cur)
	{
		if (cur == pos)
		{

			if (*pplist == pos)//如果pos处于链表头那就代表是头删
			{
				*pplist = cur->next;
				free(cur);
				cur = *pplist;
			}
			else//将它的前继结点指向的指针绕过,指向它的后继结点
			{
				prev->next = cur->next;
				free(cur);
				cur = prev->next;
			}
		}
		else
		{
			prev = cur;
			cur = cur->next;
		}
	}
}

算法思路:

(1)声明——指针pplist指向链表头;

(2)当cur不等于pos时,就往后遍历链表,让cur的指针向后移动,不断指向下一个结点

(3)若pos等于空,就代表这个链表不存在;

(4)单链表删除的标准语句 prev->next = cur->next;  free(cur); cur = prev->next;

注;

这一段算法代码里,我们又用到了另一个C语言的标准函数free。它的作用就是让系统回收一个Node结点,释放内存。

3.4、单链表打印

void SListPrint(SListNode* plist)
{
	SListNode* cur = plist;
	while (cur)//遍历到空就停止
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

3.5、单链表查找

SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	SListNode* cur = plist;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

3.6、单链表的销毁

void SListDestroy(SListNode** pplist)
{
	free(*pplist);
	*pplist = NULL;
}

4、源码

注:由于头插、头删、尾插、尾删和任意位置的插入和删除是差不多,这里直接放源码

4.1、SList.h 

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;

// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsert(SListNode ** pplist,SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListErase(SListNode ** pplist,SListNode* pos);
// 单链表的销毁
void SListDestroy(SListNode**pplist);

4.2、SList.c

#include"SList.h"
SListNode* BuySListNode(SLTDateType x)
{
	SListNode* new = (SListNode*)malloc(sizeof(SListNode));
	if (new == NULL)
	{
		perror("malloc fail:");
		exit(-1);
	}
	new->data = x;
	new->next = NULL;
	return new;
}
void SListPushBack(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	SListNode* new = BuySListNode(x);
	SListNode* tail = *pplist;
	if (*pplist == NULL)
	{
		*pplist = new;
	}
	else
	{
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = new;
	}
}
void SListPrint(SListNode* plist)
{
	SListNode* cur = plist;
	while (cur)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}
void SListPushFront(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	SListNode* new = BuySListNode(x);
	new->next = *pplist;
	*pplist = new;
}
void SListPopBack(SListNode** pplist)
{
	assert(pplist);
	assert(*pplist);
	SListNode* prev = NULL;
	SListNode* tail = *pplist;
	if ((*pplist)->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		while (tail->next)
		{
			prev = tail;
			tail = tail->next;
		}
		prev->next = NULL;
		free(tail);
		tail = NULL;
	}
}
void SListPopFront(SListNode** pplist)
{
	assert(pplist);
	assert(*pplist);
	SListNode* cur = (*pplist)->next;
	free(*pplist);
	*pplist = cur;
}
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	SListNode* cur = plist;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}
void SListInsert(SListNode** pplist, SListNode* pos, SLTDateType x)
{
	assert(pplist);
	assert(pos);
	SListNode* new = BuySListNode(x);
	SListNode* prev = *pplist;
	if (*pplist == pos)
	{
		new->next = *pplist;
		*pplist = new;
	}
	else
	{
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		new->next = pos;
		prev->next = new;
	}
}
void SListErase(SListNode** pplist, SListNode* pos)
{
	assert(pplist);
	assert(*pplist);
	assert(pos);
	SListNode* prev = *pplist;
	SListNode* cur = *pplist;
	while (cur)
	{
		if (cur == pos)
		{

			if (*pplist == pos)//如果pos处于链表头那就代表是头删
			{
				*pplist = cur->next;
				free(cur);
				cur = *pplist;
			}
			else//将它的前继结点指向的指针绕过,指向它的后继结点
			{
				prev->next = cur->next;
				free(cur);
				cur = prev->next;
			}
		}
		else
		{
			prev = cur;
			cur = cur->next;
		}
	}
}
void SListDestroy(SListNode** pplist)
{
	free(*pplist);
	*pplist = NULL;
}

4.3、Test.c

#include"SList.h"
void TestSListNode()
{
	SListNode* plist = NULL;
	SListPushFront(&plist, 1);
	SListPushFront(&plist, 2);
	SListPushFront(&plist, 3);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 5);
	SListNode* pos = SListFind(plist, 3);
	SListErase(&plist,pos);
	SListPrint(plist);


}
int main()
{
	TestSListNode();

	return 0;
}

好了!我的分享到这里就结束了,有什么不足的地方请各位大佬多多指教!!!文章来源地址https://www.toymoban.com/news/detail-406819.html

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

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

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

相关文章

  • 【数据结构】单链表的简单实现

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元

    2024年02月04日
    浏览(41)
  • 【数据结构】实现单链表的增删查

    链表类和节点类的定义: 图解: 从中间位置插入: 图解:假定index=2 尾插: 删除当前线性表中索引为index的元素,返回删除的元素值: 图解: 删除当前线性表中第一个值为element的元素: 删除当前线性表中所有值为element的元素: 将当前线性表中index位置的元素替换为eleme

    2024年02月14日
    浏览(39)
  • 数据结构:单链表的实现(C语言)

    个人主页 : 水月梦镜花 个人专栏 : 《C语言》 《数据结构》 本博客将要实现的无头单向不循环链表。 我们将节点定义为如下结构: 其成员变量有data,next。 将int重命名为STLDataType,方便我们以后修改数据域的内容。 动态申明一个空间,来放置数据。如下: 将data的内容置

    2024年02月14日
    浏览(36)
  • 【数据结构】 链表简介与单链表的实现

    在【数据结构】 ArrayList简介与实战中我们已经熟悉了ArrayList的使用,并且进行了简单模拟实现。通过源码知道,ArrayList底层使用数组来存储元素 由于其底层是一段连续空间, 当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为

    2024年02月12日
    浏览(37)
  • 初阶数据结构之单链表的实现(四)

    链表的概念 :链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。 所谓的逻辑结构其实就是能让我们自己能够更好的理解这个东西是什么?那么我们就用画图来理解理解吧!!在单链表中,存放着两个量,一个

    2024年02月06日
    浏览(25)
  • 数据结构——单链表的实现(c语言版)

    前言           单链表作为顺序表的一种,了解并且熟悉它的结构对于我们学习更加复杂的数据结构是有一定意义的。虽然单链表有一定的缺陷,但是单链表也有它存在的价值, 它也是作为其他数据结构的一部分出现的,比如在图,哈希表中。 目录 1.链表节点的结构 2.头插

    2024年02月13日
    浏览(38)
  • 【数据结构】单链表的增删查改(C实现)

    优势 : 可通过 下标i (数据连续(物理空间连续)) 便捷查询查找顺序表中的信息,也会在后面的 排序算法 和 堆算法 中尽显身手 问题 : 在头部/中间的插入与删除需要 挪动数据 ,时间复杂度为O(N),效率低; 增容需要申请新空间, 可能会拷贝数据 ,释放旧空间,会有

    2024年02月05日
    浏览(33)
  • [C语言][数据结构][链表] 单链表的从零实现!

    目录 零.必备知识 1.一级指针 二级指针 2. 节点的成员列表     a.数据     b.指向下一个节点的指针. 3. 动态内存空间的开辟 (malloc-calloc-realloc) 一.单链表的实现与销毁          1.1 节点的定义         1.2 单链表的尾插         1.3 单链表的头插         1.4 单链表的尾删  

    2024年04月11日
    浏览(36)
  • 【数据结构】单链表的增删查改(C语言实现)

    在上一节中我们提到了顺序表有如下缺陷: 在头部/中间的插入与删除需要挪动数据,时间复杂度为O(N),效率低; 增容需要申请新空间,可能会拷贝数据,释放旧空间,会有不小的消耗; 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容

    2024年02月06日
    浏览(36)
  • 【数据结构】C语言实现单链表的基本操作

    大家好,很高兴又和大家见面啦!!! 在上一篇中,我们详细介绍了单链表的两种创建方式——头插法与尾插法,相信大家现在对这两种方式都已经掌握了。今天咱们将继续介绍单链表的基本操作——查找、插入与删除。在开始今天的内容之前,我们先通过尾插法创建一个单

    2024年02月03日
    浏览(40)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包