单向无头链表实现

目录

1. 为什么要有链表?

2. 链表的种类

 3. 具体功能实现

(1)节点结构体定义

(2)申请节点

(3)尾插

(4)尾删

(5)头插

(6)头删

(7)查找

(8)指定位置插入

(9)插入指定位置后面

(10)消除指定位置元素

(11)消除指定位置后的数据

(12)打印链表

(13)销毁链表

4. 完整代码

1.  slist.c

2.  slist.h

 3. 测试文件


1. 为什么要有链表?

上篇文章我们介绍了顺序表,顺序表有很多缺陷比如

1. 空间不够需要增容,增容需要付出代价

2. 为了避免频繁扩容,我们满了基本上都是扩2倍,可能会导致一定的空间浪费

3. 要求数据从开始位置连续存储,我们在头部或中间插入删除数据,需要挪动数据,效率不高

 那有人就针对顺序表的诸多缺陷,设计出了链表

链表的优缺点如下:

优点:
按需申请空间,不用了就释放空间,头部中间插入删除数据不需要挪动数据,不存在空间浪费。

缺点:

每存一个数据都要存一个指针去链接后面的内存节点,不支持随机访问(用下标直接访问第i个)

2. 链表的种类

单向或双向,带头或不带头,循环或不循环

共八种

最常用的为

1. 无头单向非循环链表

结构简单,更多作为其他数据结构的子结构

2. 带头双向循环链表 

结构复杂,一般用于单独存储数据,实际使用中结构复杂实现简单

 3. 具体功能实现

(1)节点结构体定义
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
typedef int SLTDataType;

typedef struct SListNode
{
	int data;
	struct SListNode* next;

}SListNode;

data 用来存储数据

next用来存储下一个节点的地址

(2)申请节点

插入数据时节省代码量

SListNode* BuySListNode(SLTDataType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}
(3)尾插

在链表的末尾链接上一个节点

void SListPushBack(SListNode** phead, SLTDataType x)
{	 
	
	SListNode* newnode = BuySListNode(x);
	if (*phead == NULL)
	{
		*phead = newnode;
	}
	else
	{
		SListNode* tail = *phead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}


}
(4)尾删

删除链表最末尾的那个节点

void SListPopBack(SListNode** phead)
{	
	if (*phead == NULL)
		return;
	//assert(*phead!=NULL);
	if ((*phead)->next == NULL)
	{
		free(*phead);
		*phead = NULL;

	}
	else
	{
		SListNode* tail = *phead;
		SListNode* t = tail;

		while (tail->next != NULL)
		{
			t = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		t->next = NULL;
		//SListNode* tail = *phead;
	    //while (tail->next->next != NULL)
	    //{
	    //	tail = tail->next;
     	//}
	    //free(tail->next);
    	//tail->next = NULL;
	}



}
(5)头插

在链表头部插入数据

void SListPushFront(SListNode** phead, SLTDataType x)
{
	SListNode* newnode = BuySListNode(x);
	newnode->next = *phead;
	*phead = newnode;
}
(6)头删

删除链表头部的数据

void SListPopFront(SListNode** phead)
{
	if (*phead == NULL)
		return;
	SListNode* front=(*phead)->next;
	free(*phead);
	*phead = front;
}
(7)查找

查找链表中的某个数据,返回地址,找不到返回空指针

SListNode* SListFind(SListNode* phead, SLTDataType x)
{
	SListNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return  NULL;
}
(8)指定位置插入

根据给的地址插入数据(插入到指定位置前面)

void SListInsert(SListNode** phead, SListNode* pos, SLTDataType x)//pos配合查找函数
{
	
	SListNode* newnode = BuySListNode(x);
	if (*phead == pos)
	{
		void SListPopFront(phead);
	}
	//找到pos的前一位置
	else
	{ 
		SListNode* posPrey = *phead;
		while (posPrey->next != pos)
		{
			posPrey = posPrey->next;
		}
		posPrey->next = newnode;
		newnode->next = pos;
	}
}
(9)插入指定位置后面
void SListInsertTail(SListNode* pos, SLTDataType x)
{
	assert(pos);
	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}
(10)消除指定位置元素
void SListErase(SListNode** phead, SListNode* pos)
{
	assert(head && (*head));
	assert(pos);
	if (*phead == pos)
	{
		*phead = (*phead)->next;
		free(pos);
		pos = NULL;
	}
	else
	{
	    SListNode* prev = *phead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
(11)消除指定位置后的数据
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	if (pos == NULL)
	{
		exit(-1);
	}
	SListNode* next = pos->next;
	pos->next = next->next;
	free(next);
	next = NULL;
}
(12)打印链表
void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

(13)销毁链表

使用结束后要销毁

void SListDestroy(SListNode** phead)
{
	assert(phead && *phead);
	SListNode* plist = *phead;
	while (plist->next != NULL)
	{
		plist = plist->next;
		free(*phead);
		*phead = plist;
	}
	free(*phead);
	*phead = NULL;

}

4. 完整代码

1.  slist.c
#define _CRT_SECURE_NO_WARNINGS h
#include"sllist.h"

SListNode* BuySListNode(SLTDataType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

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

void SListPushBack(SListNode** phead, SLTDataType x)
{	 
	
	SListNode* newnode = BuySListNode(x);
	if (*phead == NULL)
	{
		*phead = newnode;
	}
	else
	{
		SListNode* tail = *phead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}


}

void SListPushFront(SListNode** phead, SLTDataType x)
{
	SListNode* newnode = BuySListNode(x);
	newnode->next = *phead;
	*phead = newnode;
}

void SListPopBack(SListNode** phead)
{	
	if (*phead == NULL)
		return;
	//assert(*phead!=NULL);
	if ((*phead)->next == NULL)
	{
		free(*phead);
		*phead = NULL;

	}
	else
	{
		SListNode* tail = *phead;
		SListNode* t = tail;

		while (tail->next != NULL)
		{
			t = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		t->next = NULL;
		//SListNode* tail = *phead;
	    //while (tail->next->next != NULL)
	    //{
	    //	tail = tail->next;
     	//}
	    //free(tail->next);
    	//tail->next = NULL;
	}



}

void SListPopFront(SListNode** phead)
{
	if (*phead == NULL)
		return;
	SListNode* front=(*phead)->next;
	free(*phead);
	*phead = front;
}

SListNode* SListFind(SListNode* phead, SLTDataType x)
{
	SListNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return  NULL;
}
void SListInsert(SListNode** phead, SListNode* pos, SLTDataType x)//pos配合查找函数
{
	
	SListNode* newnode = BuySListNode(x);
	if (*phead == pos)
	{
		void SListPopFront(phead);
	}
	//找到pos的前一位置
	else
	{ 
		SListNode* posPrey = *phead;
		while (posPrey->next != pos)
		{
			posPrey = posPrey->next;
		}
		posPrey->next = newnode;
		newnode->next = pos;
	}
}
void SListInsertTail(SListNode* pos, SLTDataType x)
{
	assert(pos);
	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}
void SListErase(SListNode** phead, SListNode* pos)
{
	assert(head && (*head));
	assert(pos);
	if (*phead == pos)
	{
		*phead = (*phead)->next;
		free(pos);
		pos = NULL;
	}
	else
	{
	    SListNode* prev = *phead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	if (pos == NULL)
	{
		exit(-1);
	}
	SListNode* next = pos->next;
	pos->next = next->next;
	free(next);
	next = NULL;
}
void SListDestroy(SListNode** phead)
{
	assert(phead && *phead);
	SListNode* plist = *phead;
	while (plist->next != NULL)
	{
		plist = plist->next;
		free(*phead);
		*phead = plist;
	}
	free(*phead);
	*phead = NULL;

}
2.  slist.h
#define _CRT_SECURE_NO_WARNINGS h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
typedef int SLTDataType;

typedef struct SListNode
{
	int data;
	struct SListNode* next;

}SListNode;

void SListPrint(SListNode* phead);
//打印
void SListPushBack(SListNode** phead, SLTDataType x);
//尾插
void SListPushFront(SListNode** phead,SLTDataType x);
//头插
void SListPopBack(SListNode** phead);
//尾删
void SListPopFront(SListNode** phead);
//头删
SListNode* SListFind(SListNode* phead, SLTDataType x);
//找位置
//在pos位置之前去插入一个节点
void SListInsert(SListNode** phead, SListNode* pos, SLTDataType x);
//在pos前面插入

//void SListInsert(SListNode* phead, int pos, SLTDataType x);

void SListErase(SListNode** phead, SListNode* pos);
//找坐标删除
void SListEraseAfter(SListNode* pos);
//删除坐标后面的值

void SListDestroy(SListNode** phead)
 3. 测试文件
#define _CRT_SECURE_NO_WARNINGS h
#include"sllist.h"
#include<stdio.h>
#include<stdlib.h>
void TestSList1()
{
	SListNode* plist = NULL;//初始值
	SListPushBack(&plist, 1);
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 3);
	SListPushFront(&plist, 4);
	SListPushFront(&plist, 5);
	SListPrint(plist);
	SListPopFront(&plist);
	SListPopFront(&plist);

	SListPrint(plist);
}
void TestSList2()
{
	SListNode* plist = NULL;//初始值
	SListPushBack(&plist, 1);
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 2);

	SListNode* pos = SListFind(plist, 2);
	SListInsert(&plist ,pos,20);
	SListPrint(plist);
	//SListDestroy(&plist);
	//SListPrint(plist);
	int i = 1;
	while (pos)
	{

		printf("第%d个节点%p->%d\n", i++, pos, pos->data);
		pos = SListFind(pos->next, 2);
	}
	pos = SListFind(plist, 3);

	while(pos)
	{
		pos->data = 30;
		pos = SListFind(pos->next, 3);
	}
	SListPrint(plist);
}
typedef struct xx
{
	int* n;
}xx;
int main()
{
	TestSList2();
	//xx p;
	//int a = 0;
	//p.n = &a;
	//a = 2;
	//printf("%d", *(p.n));
	return 0;
}

这篇文章就到这里了,希望可以帮到您

(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/633455.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文本信息的二维码怎么做?在线制作文本二维码的3个步骤

现在通过二维码来展示文本信息是很常见的一种方式&#xff0c;可以将信息编辑好排版后生成二维码&#xff0c;其他人可以通过扫描生成的二维码来获取文本信息。这种方式传递起来更加的简单快捷&#xff0c;而且二维码可以长期提供内容展示效果降低了推广成本&#xff0c;在很多…

数据库系统概论(第5版)复习笔记

笔记的Github仓库地址 &#x1f446;这是笔记的gihub仓库&#xff0c;内容是PDF格式。 因为图片和代码块太多&#xff0c;放到CSDN太麻烦了&#xff08;比较懒&#x1f923;&#xff09; 如果感觉对各位有帮助的话欢迎点一个⭐\^o^/

Elasticsearch 加速在无服务器上构建 AI 搜索应用程序

作者&#xff1a;来自 Elastic Alvin Richards, Yaru Lin 今天&#xff0c;我们宣布推出 Elasticsearch Serverless 技术预览版&#xff0c;其功能包括&#xff1a; 以开发人员为中心的体验&#xff0c;通过直观的入门和相关代码示例简化创建人工智能驱动的搜索&#xff0c;所…

常态化运营,让数据安全工作落地生根!

数据安全如同城堡的基石&#xff0c;其重要性无需赘述。 数据安全防护体系的建设&#xff0c;解决数据安全措施“有”和“无”的问题&#xff1b;常态化的数据安全运营工作&#xff0c;解决的是数据安全“能用”和“好用”的问题。 因此&#xff0c;如何让数据安全成为一种常…

国赛部分复现

MISC 神秘文件 下载解压后是个pptm文件&#xff0c;内容丰富 使用010打开ppt查看 发现为PK开头&#xff0c;属于压缩包文件。复制粘贴ppt&#xff0c;修改副本后缀为.zip并解压 part1 查看属性&#xff0c;发现奇怪字符 QFCfpPQ6ZymuM3gq 根据提示Bifid chipher&#xff0c;…

2024中青杯数学建模竞赛B题药物属性预测思路代码论文分享

2024年中青杯数学建模竞赛B题论文和代码已完成&#xff0c;代码为B题全部问题的代码&#xff0c;论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解&#xff08;问题1模型的建立和求解、问题2模型的建立和求解、问题3模型的建立和求解&#xff09;、模型…

一剪梅-答赠云安客刘自果

当众网友看了笔者“边吸氧边动鼠标”的短视频之后&#xff0c;纷纷发来微信问候。其中我的远房亲戚&#xff0c;那个正在潜心写作数十万字的长篇纪实文学《川江向东流》的66岁贤弟刘自果&#xff08;号云安客&#xff0c;亦称自果居士&#xff09;&#xff0c;发来微信鼓励我&a…

图生代码,从Hello Onion 代码开始

从Hello Onion 代码开始 1&#xff0c;从代码开始 原生语言采用java 作为载体。通过注解方式实现“UI可视化元素"与代码bean之间的映射. 转换示例 2&#xff0c;运行解析原理 在执行JAVA代码期间&#xff0c;通过读取注解信息&#xff0c;转换为前端的JSON交由前端JS框…

java中的TreeMap类和Hashtable类+Map集合遍历+集合小结

一、TreeMap类 实现了Map接口&#xff0c;元素为键值对、键不可重复、值可重复 特点&#xff1a;可排序 要求&#xff1a;Key类必须实现Comparable接口 底层结构&#xff1a;红黑树 1、可排序 2、常用方法 与HashMap一致 二、Hashtable类 实现了Map接口&#xff0c;元素…

springboot+jsp校园理发店美容美发店信息管理系统0h29g

前台管理:会员管理、会员预定、开单点单、收银结帐、技师提成 后台管理:数据维护、物料管理、数据查询、报表分析、系统设置等 灵活的付款方式&#xff0c;支持现金、挂帐、会员卡&#xff0c;同时支持多种折扣方式并可按用户要求设置多种结帐类型善的充值卡管理模块:支持优惠卡…

Postman进阶功能-Mock服务与监控

大家好&#xff0c;前面跟大家分享一些关于 Postman 的进阶功能&#xff0c;当我们深入探索 Postman 的进阶功能时&#xff0c;Mock 服务与监控这两个重要方面便跃然眼前。 首先&#xff0c;Mock 服务为我们提供了一种灵活便捷的方式&#xff0c;让我们在某些实际接口尚未准备好…

IS-IS基本配置 IS-IS邻接关系

一.IS-IS基本配置 原理概述 和 OSPF 路由协议一样&#xff0c; IS-IS 也是一个应用非常广泛的 IGP 路由协议&#xff0c;很多 ISP 网络、特别是大型的ISP网络都部署了IS-IS网络协议。 RIP 、 OSPF 等许多 IGP 都是针对 IP ( Internet Protocol &#xff09;这个网络层协议而开…

【Vue】性能优化

使用 key 对于通过循环生成的列表&#xff0c;应给每个列表项一个稳定且唯一的 key&#xff0c;这有利于在列表变动时&#xff0c;尽量少的删除和新增元素。 使用冻结的对象 冻结的对象&#xff08;Object.freeze(obj)&#xff09;不会被响应化&#xff0c;不可变。 使用函…

Vue2基础及其进阶面试(一)

简单版项目初始化 新建一个vue2 官网文档&#xff1a;介绍 — Vue.js 先确保下载了vue的脚手架 npm install -g vue-cli npm install -g vue/cli --force vue -V 创建项目 vue create 自己起个名字 选择自己选择特性 选择&#xff1a; Babel&#xff1a;他可以将我们写…

springboot+jwt+shiro+vue+elementUI+axios+redis+mysql完成一个前后端分离的博客项目

目录 简易博客项目(springbootjwtshirovueelementUIaxiosredismysql)第一章 整合新建springboot,整合mybatisplus第一步 创建项目(第八步骤就行)数据库:1、 修改pom.xml2、修改配置文件3、创建数据库vueblog然后执行下面命令生成表 第二步 配置分页MybatisPlusConfig生成代码(d…

佩戴安全头盔监测识别摄像机

佩戴安全头盔是重要的安全措施&#xff0c;尤其在工地、建筑工程和工业生产等领域&#xff0c;安全头盔的佩戴对于工人的生命安全至关重要。为了更好地管理和监控佩戴安全头盔的情况&#xff0c;监测识别摄像机成为了一项重要的工具。监测识别摄像机可以通过智能技术监测并记录…

紫光同创PGL22G开发板|盘古22K开发板,国产FPGA开发板,接口丰富

盘古22K开发板是基于紫光同创Logos系列PGL22G芯片设计的一款FPGA开发板&#xff0c;全面实现国产化方案&#xff0c;板载资源丰富&#xff0c;高容量、高带宽&#xff0c;外围接口丰富&#xff0c;不仅适用于高校教学&#xff0c;还可以用于实验项目、项目开发&#xff0c;一板…

数据开放最全sql面试合集(leetcode)

关注公众号“大数据领航员"领取PDF版本和大数据面经 https://leetcode-cn.com/problemset/database/ 题目都是leetcode 上了可以点击题目会有相应的链接 由于个人比较喜欢用开窗函数&#xff0c;所以都优先用了开窗 &#xff0c;当然这些并不一定都是最优解&#xff0c…

【Linux取经路】进程通信——共享内存

文章目录 一、直接原理1.1 共享内存的的申请1.2 共享内存的释放 二、代码演示2.1 shmget2.1.1 详谈key——ftok 2.2 创建共享内存样例代码2.3 获取共享内存——进一步封装2.4 共享内存挂接——shmat2.5 共享内存去关联——shmdt2.6 释放共享内存——shmctl2.7 开始通信2.7.1 pr…

Git简单理解

Git 概述 Git 是一个免费的开源的&#xff0c;分布式版本控制系统&#xff0c;可以快速高效的处理从小型到大型的各种项目 Git占地面积小&#xff0c;性能极快&#xff0c;具有廉价的本地库&#xff0c;方便的暂存区和多个工作流分支等特性 版本控制 版本控制是一种记录文件…