单向无头链表实现

news2024/11/20 21:19:35

目录

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ᵒᵛᵉᵧₒᵤ❤

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CST电磁软件工作室时域求解器和频域求解器介绍【仿真入门】

时域求解器vs.频域求解器 不同情形下选择Time Domain Solver还是Frequency Domain Solver? 三维电磁仿真支持的具有代表性的两种求解器-Time Domain Solver和Frequency DomainSolver以不同的方式计算出仿真结果&#xff0c;所以根据仿真的情形可以选择性地使用两个Solver。 …

BCD编码Java实现

最常用的BCD编码&#xff0c;就是使用"0"至"9"这十个数值的二进码来表示。这种编码方式&#xff0c;在称之为“8421码”&#xff08;日常所说的BCD码大都是指8421BCD码形式&#xff09;。除此以外&#xff0c;对应不同需求&#xff0c;各人亦开发了不同的编…

图论-最短路算法

1. Floyd算法 作用&#xff1a;用于求解多源最短路&#xff0c;可以求解出任意两点的最短路 利用动态规划只需三重循环即可&#xff08;动态规划可以把问题求解分为多个阶段&#xff09;定义dp[k][i][j]表示点i到点j的路径&#xff08;除去起点终点&#xff09;中最大编号不超…

React类组件生命周期详解

在React的类组件中&#xff0c;从组件创建到组件被挂载到页面中&#xff0c;这个过程react存在一系列的生命周期函数&#xff0c;最主要的生命周期函数是componentDidMount、componentDidUpdate、componentWillUnmount 生命周期图例如下 1. componentDidMount组件挂载 如果你…

【NLP】词性标注

词 词是自然语言处理的基本单位&#xff0c;自动词法分析就是利用计算机对词的形态进行分析&#xff0c;判断词的结构和类别。 词性&#xff08;Part of Speech&#xff09;是词汇最重要的特性&#xff0c;链接词汇和句法 词的分类 屈折语&#xff1a;形态分析 分析语&#…

来盘点我的校园生活(3)

来公布上期数学题答案:12 你算对了吗&#xff1f; 今天我们班真是炸开了锅。事情是这样的&#xff0c;我今天早晨上学&#xff0c;学校不让早到&#xff0c;但我一个不小心早到了&#xff0c;主任的规定是尽量不早到&#xff0c;早到不扣分&#xff0c;倒要站在那儿背书&…

MYSQL 集群

1.集群目的:负载均衡 解决高并发 高可用HA 服务可用性 远程灾备 数据有效性 类型:M M-S M-S-S M-M M-M-S-S 原理:在主库把数据更改(DDL DML DCL&#xff09;记录到二进制日志中。 备库I/O线程将主库上的日志复制到自己的中继日志中。 备库SQL线程读取中继日志…

css使用clip-path裁剪出不规则图形并绑定点击事件

点击图片的红色区域触发事件 点击图片黑色不触发点击事件&#xff0c;代码演示效果如下&#xff1a; 代码演示效果 1.png&#xff08;尺寸 200*470&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><…

Spring Boot:SpringBoot 如何优雅地定制JSON响应数据返回

一、前言 目前微服务项目中RESTful API已经是前后端对接数据格式的标配模式了&#xff0c;RESTful API是一种基于REST&#xff08;Representational State Transfer&#xff0c;表述性状态转移&#xff09;原则的应用程序编程接口&#xff08;Application Programming Interfac…

ubuntu手动替换源后,更新源时提示“仓库.... jammy Release“ 没有Release文件

问题如图所示&#xff0c;由于问题不好定位&#xff0c;我就从替换源&#xff0c;以及解决错误提示这两个步骤&#xff0c;来解决其中可能存在的问题。 1、替换源 这一步骤&#xff0c;网上的资料可以搜到很多&#xff0c;我跟着做了之后&#xff0c;总会冒出来各种各样的小问…

TikTok矩阵管理系统:品牌增长的新引擎

随着社交媒体的快速发展&#xff0c;TikTok已成为全球最受欢迎的短视频平台之一。品牌和企业纷纷涌入这个平台&#xff0c;寻求新的增长机会。然而&#xff0c;随着内容的激增和用户群体的多样化&#xff0c;管理TikTok账号变得越来越复杂。这时&#xff0c;TikTok矩阵管理系统…

Vue2全局封装modal弹框

Vue2全局封装modal弹框使用&#xff1a; 一.components下封装 1.index.js import ModalCheck from ./modal-check.vue export default ModalCheck2.modal-check.vue <template><div><Modalv-model"selSingleShow":title"editTitle(convertCa…

Docker Hub注册及上传自定义镜像

说明&#xff1a;本文介绍如何注册Docker Hub&#xff0c;及将自己自定义镜像上传到Docker Hub上&#xff1b; 注册Docker Hub 浏览器输入&#xff1a;http://hub.docker.com/&#xff0c;进入Docker Hub官网 注&#xff1a;如果无法访问&#xff0c;可在GitHub上下载一个Ste…

PPT大珩助手新功能-生成迷宫

大珩助手是一款功能丰富的办公软件插件&#xff0c;它主要分为两个版本&#xff1a;PPT大珩助手和Word大珩助手。这两个版本都旨在提高用户在处理演示文稿和文档时的效率。 PPT大珩助手 这是一款专门为Microsoft PowerPoint设计的插件。它提供了多种功能&#xff0c;例如素材…

Outlook 开启smtp配置

微软 Outlook 邮箱各种服务详细信息 服务类型服务器地址端口加密方法POPoutlook.office365.com995TLSIMAPoutlook.office365.com993TLSSMTPsmtp.office365.com587STARTTLS 然而仅仅有以上信息还不够&#xff0c;需要获取服务密码 (授权码) 才能够使用 POP, IMAP, SMTP 这三种…

面了一个程序员,因为6休1拒绝了我

人一辈子赖以生存下去的主要就考虑三件事&#xff0c;职业&#xff0c;事业&#xff0c;副业&#xff0c;有其1-2都是很不错的。如果还没到40岁&#xff0c;那不妨提前想下自己可能遇到的一些情况&#xff0c;提前做一些准备&#xff0c;未雨绸缪些。 今年整体就业大环境也一般…

SpringIOC和DI注解开发

xml配置 注解方式 6个注解&#xff1a; IOC用于对象创建&#xff1a; Controller 控制层 Service 业务层 Repository 持久层 Conponent 普通组件对象的创建 DI用于依赖注入&#xff1a; Autowired //默认按照类型 配合Qualifier使用 Qualifier //指定…

java文档管理系统的设计与实现源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的文档管理系统的设计与实现。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 文档管理系统的…

十年了。网络连接又中断了,原来是因为...

爷青回&#xff01; 90 后的朋友应该都是玩过或听说过 DNF 这个游戏&#xff0c;反正这个有是伴随着我的整个童年时光&#xff0c;当年放学就跑去上网&#xff0c;就为了刷疲劳、爆装备&#xff0c;”挥霍“了大把时光。最近他出手游了。 很早就看到过广告&#xff0c;感觉就…

VMware-计算超分解释

一、如图 二、官网解释 虚拟机CPU或内存 消耗&#xff08;Consumed&#xff09;&#xff1a;表示虚拟机实际使用的资源量。这包括CPU、内存、磁盘等资源的实际使用量。消耗量是实际分配给虚拟机的资源数量&#xff0c;而不仅仅是它们被配置的数量。 活动&#xff08;Active&…