【数据结构与算法】单链表的增删查改(附源码)

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

单链表的增删改查代码,数据结构与算法,链表,数据结构,c语言,算法,开发语言

单链表的增删改查代码,数据结构与算法,链表,数据结构,c语言,算法,开发语言 

这么可爱的猫猫不值得点个赞吗😽😻

目录

一.链表的概念和结构

二.单链表的逻辑结构和物理结构

1.逻辑结构

 2.物理结构

三.结构体的定义

四.增加

1.尾插   SListpushback

2.头插  SListpushfront

五.删除

1.尾删  SListpopback

2.头删  SListpopfront

六.查找  插入  释放   打印

1.查找   SListfind

2.插入  SListinsert

3.释放  SListerase

4.打印  SListprint

七.源码

1.SList.h

2.SList.c

3.test.c


一.链表的概念和结构

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的

链表其实有很多种类:

1.单向  双向

2.带头  不带头

3.循环  不循环

其中共能组合出8种形式的链表;

这篇文章讲的是结构最简单的链表,也就是单向不带头不循环链表,即单链表

单链表中的元素称为节点,节点有一个数据data,还有一个结构体指针next 存储下一个节点的地址,最后一个节点的next是NULL。

二.单链表的逻辑结构和物理结构

1.逻辑结构

单链表的增删改查代码,数据结构与算法,链表,数据结构,c语言,算法,开发语言

 2.物理结构

单链表的增删改查代码,数据结构与算法,链表,数据结构,c语言,算法,开发语言

三.结构体的定义

typedef int SLdatatype;  //对数据类型重定义,方便后续更改

typedef struct SListNode
{
	SLdatatype data;
	struct SListNode* next;
}SLNode;

四.增加

1.尾插   SListpushback

想要实现尾插,就要先找到尾节点,但要注意,当链表是空时,就没有尾节点,这个时候直接插入就行了;

我们可以申请一个新的节点newnode,然后插入链表中,由于尾插和头插都需要申请新的节点,所以我们可以将这封装成一个函数

注意,不管是尾插还是头插,最后都会使链表发生改变,所以我们要传二级指针进去

找尾节点时,while里的循环条件要写成 tail->next !=NULL  

请看逻辑结构:

单链表的增删改查代码,数据结构与算法,链表,数据结构,c语言,算法,开发语言

申请新节点 BuySListNode

SLNode* BuySListNode(SLdatatype x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	assert(newnode);
	newnode->data = x;  //x是要插入的数据
	newnode->next = NULL;
	return newnode;
}

尾插 SListpushback

单链表的增删改查代码,数据结构与算法,链表,数据结构,c语言,算法,开发语言

 文章来源地址https://www.toymoban.com/news/detail-784282.html

void SListpushback(SLNode** pphead,SLdatatype x)  //注意传的是二级指针
{
	SLNode* newnode = BuySListNode(x);
	if (*pphead == NULL)   //判断链表是否为空
	{
		*pphead = newnode;
	}
	else
	{
		SLNode* tail = *pphead;  //寻找尾节点
		while (tail->next != NULL)   //注意这里不能写成 while(tail!=NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

2.头插  SListpushfront

头插时只需让新节点的 next 指向旧的头节点,然后再把 newnode 赋给头节点,使之成为新的头节点,即使是空表也没关系,newnode 会直接成为头节点

单链表的增删改查代码,数据结构与算法,链表,数据结构,c语言,算法,开发语言

 

void SListpushfront(SLNode** pphead, SLdatatype x)
{
	SLNode* newnode = BuySListNode(x);
		newnode->next = *pphead;
		*pphead = newnode;
}

五.删除

1.尾删  SListpopback

尾删前,我们需要判断:

1.若为空表,则直接结束函数;

2.若链表中只有一个节点,则直接 free 头节点,然后置为NULL;

3.寻找尾节点 tail 和尾节点的前一个节点 pre ,因为我们释放掉尾节点后,pre就成为了新的尾节点,而尾节点的 next 是 NULL ,所以我们需要找到尾节点的前一个节点。

找尾的方法和之前的一样。

void SListpopback(SLNode** pphead)
{
	if (*pphead == NULL)
	{
		return;
	}
	else if ((*pphead)->next == NULL)  //注意这里因为优先级的问题,*pphead 要打括号
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLNode* pre = NULL;
		SLNode* tail = *pphead;
		while (tail->next != NULL)
		{
			pre = tail;   //记录 tail 的前一个节点
			tail = tail->next;
		}
		pre->next = NULL;  //next 置为NULL
	}
}

2.头删  SListpopfront

在头删前:

1.判断是否为空表;

2.定义一个 next 用来保存头节点中的 next  ,释放完后,这个 next 就成为了新的头节点。

void SListpopfront(SLNode** pphead)
{
	if (*pphead == NULL)
	{
		return;
	}
	else
	{
		SLNode* next = (*pphead)->next;
		free(*pphead);
		*pphead = next;
	}
}

六.查找  插入  释放   打印

1.查找   SListfind

在插入和释放前,都需要调用 find 函数,来找到希望插入或是释放的位置。

SLNode* SListfind(SLNode* phead, SLdatatype x)
{
	SLNode* pos = phead;
	while (pos)
	{
		if (pos->data == x)
		{
			return pos;
		}
		pos = pos->next;
	}
}

2.插入  SListinsert

如果是链表中只有一个节点,就变成了头插,只需要调用头插函数就行了,如果是空表也不用担心,可以设置成不调用函数;

在插入前,需要找到指定位置 pos 的前驱 pre,

使pre->next=newnode  , newnode->next=pos

如图所示,假设在3的前一个位置插入数据:

单链表的增删改查代码,数据结构与算法,链表,数据结构,c语言,算法,开发语言

 

void SListinsert(SLNode** pphead, SLNode* pos,SLdatatype x)
{
	SLNode* newnode = BuySListNode(x);
	if (pos->next == NULL)
	{
		SListpushfront(pphead, x);
	}
	else
	{
		SLNode* pre = *pphead;
		while (pre->next != pos)
		{
			pre = pre->next;
		}
		pre->next = newnode;
		newnode->next = pos;
	}
}

3.释放  SListerase

释放前:

1.如果只有一个节点,则直接释放头节点,再置为空即可;

2.如果不止一个节点,还需找到要释放的位置的前一个节点 pre ,将 pre 的 next 指向 pos 的next,然后再释放;

如图所示,假设要释放掉3这个节点:

单链表的增删改查代码,数据结构与算法,链表,数据结构,c语言,算法,开发语言

 

void SListerase(SLNode** pphead, SLNode* pos, SLdatatype x)
{
	if (pos->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLNode* pre = *pphead;
		while (pre->next !=pos)
		{
			pre = pre->next;
		}
		pre->next = pos->next;
		free(pos);
	}
}

4.打印  SListprint

虽然可以直接用头节点 phead 遍历,但博主还是推荐定义一个新的结构体指针  cur  ,把phead 的值赋给 cur ,会显得更优雅;

注意这里的 while 里的式子要写成  cur  ,如果 写成 cur->next ,那么最终打印出来的结果会少一个节点的数据。

void SListprint(SLNode* phead)
{
	SLNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

七.源码

1.SList.h

#define _CRT_SECURE_NO_WARNINGS


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLdatatype;

typedef struct SListNode
{
	SLdatatype data;
	struct SListNode* next;
}SLNode;


void SListprint(SLNode* phead);   //打印

void SListpushback(SLNode** pphead,SLdatatype x);   //尾插

void SListpushfront(SLNode** pphead, SLdatatype x);   //头插

void SListpopfront(SLNode** pphead);   //头删

void SListpopback(SLNode** pphead);   //尾删

SLNode* SListfind(SLNode* phead,SLdatatype x);   //查找

void SListinsert(SLNode** pphead, SLNode* pos,SLdatatype x);   //插入

void SListerase(SLNode** pphead, SLNode* pos, SLdatatype x);   //释放

2.SList.c

#define _CRT_SECURE_NO_WARNINGS

#include "SList.h"


void SListprint(SLNode* phead)
{
	SLNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}


SLNode* BuySListNode(SLdatatype x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	assert(newnode);
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

void SListpushback(SLNode** pphead,SLdatatype x)
{
	SLNode* newnode = BuySListNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLNode* tail = *pphead;  //寻找尾节点
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}


void SListpushfront(SLNode** pphead, SLdatatype x)
{
	SLNode* newnode = BuySListNode(x);
		newnode->next = *pphead;
		*pphead = newnode;
}


void SListpopfront(SLNode** pphead)
{
	if (*pphead == NULL)
	{
		return;
	}
	else
	{
		SLNode* next = (*pphead)->next;
		free(*pphead);
		*pphead = next;
	}
}


void SListpopback(SLNode** pphead)
{
	if (*pphead == NULL)
	{
		return;
	}
	else if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLNode* pre = NULL;
		SLNode* tail = *pphead;
		while (tail->next != NULL)
		{
			pre = tail;
			tail = tail->next;
		}
		pre->next = NULL;
	}
}


SLNode* SListfind(SLNode* phead, SLdatatype x)
{
	SLNode* pos = phead;
	while (pos)
	{
		if (pos->data == x)
		{
			return pos;
		}
		pos = pos->next;
	}
}


void SListinsert(SLNode** pphead, SLNode* pos,SLdatatype x)
{
	SLNode* newnode = BuySListNode(x);
	if (pos->next == NULL)
	{
		SListpushfront(pphead, x);
	}
	else
	{
		SLNode* pre = *pphead;
		while (pre->next != pos)
		{
			pre = pre->next;
		}
		pre->next = newnode;
		newnode->next = pos;
	}
}



void SListerase(SLNode** pphead, SLNode* pos, SLdatatype x)
{
	if (pos->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLNode* pre = *pphead;
		while (pre->next !=pos)
		{
			pre = pre->next;
		}
		pre->next = pos->next;
		free(pos);
	}
}

3.test.c

博主写的主函数只是用来测试单链表的,写起主函数来也不难,大家可以自行编写。

#include "SList.h"


void testSList1()
{
	SLNode* plist = NULL;
	
	SListpushback(&plist,1);
	SListpushback(&plist,2);
	SListpushback(&plist,3);
	SListpushback(&plist,4);
	SListprint(plist);
	SListpushfront(&plist, 0);
	SListprint(plist);
	SListpopfront(&plist);
	SListpopfront(&plist);
	SListpopfront(&plist);
	SListprint(plist);
	SListpopback(&plist);
	SListpopback(&plist);
	SListpopback(&plist);
	SListprint(plist);
}

void testSList2()
{
	SLNode* plist = NULL;
	SListpushback(&plist, 1);
	SListpushback(&plist, 2);
	SListpushback(&plist, 3);
	SListpushback(&plist, 4);
	SLNode* pos = SListfind(plist, 3);
	if (pos)
	{
		SListinsert(&plist,pos, 20);
		SListprint(plist);
	}
	pos = SListfind(plist, 2);
	if (pos)
	{
		SListerase(&plist,pos,2);
		SListprint(plist);
	}
	
}

int main()
{
	//testSList1();
	testSList2();
	return 0;
}

八.单链表的一些问题

在单链表中,要想找到某一个数据,就需要从头节点开始,所以单链表是非随机存取的存储结构,且要想对单链表进行一些操作,总是要找到前驱节点,有时还需判断一些特殊情况,有什么办法能解决这些问题呢?

博主将在下篇双向带头循环链表中讲解,敬情期待~


🤩🥰本篇文章到此就结束了,如有错误或是建议,欢迎小伙伴们提出~😍😃

🐲👻希望可以多多支持博主哦~🥰😍

🤖🐯谢谢你的阅读~👻🦁

单链表的增删改查代码,数据结构与算法,链表,数据结构,c语言,算法,开发语言

 

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

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

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

相关文章

  • 【数据结构】链表:带头双向循环链表的增删查改

    本篇要分享的内容是带头双向链表,以下为本片目录 目录 一、链表的所有结构 二、带头双向链表 2.1尾部插入 2.2哨兵位的初始化 2.3头部插入 2.4 打印链表 2.5尾部删除 2.6头部删除  2.7查找结点 2.8任意位置插入 2.9任意位置删除  在刚开始接触链表的时候,我们所学仅仅所学的

    2024年02月05日
    浏览(91)
  • 数据结构入门(C语言)顺序表的增删查改

    本章会用C语言来描述数据结构中的顺序表,实现简单的增删查改操作,其中头文件包含在新建的头文件SeqList.h内,顺序表的实现在新建的Seqlist.c内,主函数Text.c将会实现菜单,方便我们进行功能的选择。 顺序表是用一段物理地址 连续 的存储单元依次存储数据元素的线性结构

    2024年02月03日
    浏览(47)
  • 【数据结构】双向链表的增删查改(C 代码实现)

    引入双向链表:关于单链表的问题与讨论 单链表存在的毛病: 因为单链表 只能单向 遍历链表, 对于 前插 这个操作,单链表必 须得找到所需前插节点位置的前一个 ,那么这时就得 从头指针重新遍历一次 链表,会造成时间复杂度大大增加。 没有头节点(哨兵位)无法删除

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

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

    2024年02月14日
    浏览(163)
  • 【数据结构】单向链表的增删查改以及指定pos位置的插入删除

    目录  单向链表的概念及结构  尾插 头插 尾删 ​编辑  头删  查找  在pos位置前插  在pos位置后插  删除pos位置  删除pos的后一个位置 总结 代码  概念:链表是一种 物理存储结构上非连续 、非顺序的存储结构,数据元素的 逻辑顺序 是通过链表中的 指针链接 次序实现的

    2024年02月05日
    浏览(48)
  • 【数据结构与算法】单链表的排序算法(选择,冒泡,递归)

    目录 选择排序 冒泡排序 快速排序 合并两条链表并排序 选择排序 链表的选择排序思想与数组的排序类似,但是链表需要先找到里面最小或者最大的值,然后将这个值用改链语句进行操作 我们先看这个改链语句的操作(min是笔者打错了应该是max,但是图已经画好了就没有改)

    2024年02月04日
    浏览(56)
  • 单链表的建立(头插法、尾插法)(数据结构与算法)

    如果要把很多个数据元素存到一个单链表中,如何操作? 1.初始化一个单链表 2. 每次取一个数据元素,插入到表尾/表头 尾插法建立的单链表元素顺序与输入数据集合的顺序相同,即按照输入数据的顺序排列。 使用尾插法建立单链表的一个常见应用是在计算机科学中进行数据

    2024年04月11日
    浏览(44)
  • 【数据结构入门】顺序表详解(增删查改)

    目录 顺序表的基本概念 动态顺序表的实现 初始化 插入 尾插法 头插法 指定位置之前插入 删除 尾删法 头删法 指定位置删除 查找 销毁 什么是顺序表? 顺序表是用一段 物理地址连续的存储单元 依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的

    2024年04月17日
    浏览(34)
  • 【数据结构与算法】深入浅出:单链表的实现和应用

      🌱博客主页:青竹雾色间. 😘博客制作不易欢迎各位👍点赞+⭐收藏+➕关注  ✨ 人生如寄,多忧何为  ✨ 目录 前言 单链表的基本概念 节点 头节点 尾节点 单链表的基本操作 创建单链表 头插法: 尾插法: 插入(增)操作  删除(删)操作: 查找(查)操作: 修改(改

    2024年02月08日
    浏览(74)
  • C语言简单的数据结构:单链表的有关算法题(2)

    接着我们介绍后面的三道题,虽然代码变多了但我们的思路更加通顺了 题目链接:https://leetcode.cn/problems/merge-two-sorted-lists/ 创建新链表,遍历原链表,将节点值小的进行尾插到新链表中 这里要多次进行对NULL的判断,开始传入列表,中间newHead的判断,循环出来一个为NULL的判断

    2024年04月15日
    浏览(63)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包