单链表---结构体实现

news2024/11/20 9:16:37

定义

链表称为线性表的链式存储,顺序表逻辑上相邻的数据,存储位置也相邻。链表逻辑上相邻的数据,存储位置是随机分布在内存的各个位置上的。

对于每一个结点,定义的结构体是:

typedef struct _LinkNode 
{
	int date;				//数据域,存储数据,这里是int类型的数据
	struct _LinkNode* next; // 指针域,指向了后继元素(下一个结点)的地址
}LinkNode , LinkList;       //两个别名的作用是一模一样的,只是为了区分头结点和结点

 链表的初始化

我们用一个结构体指针L来指向链表,最开始是带一个头结点的空链表,头结点的数据域一般赋值为-1,也可以存储着链表的长度。头结点的指针域指针第一个元素结点,最开始是没有元素结点的空链表(有头结点),如图:

代码实现

bool initLinkList(LinkList*& L) //参数是对结构体指针的引用
{
	L = new LinkList; //也可以写成 L = new LinkNode ;
	if (!L)
	{
		return false; // 申请内存失败,返回了一个空指针
	}
    
	L->next = NULL;
	return true;
}

链表的插入

头插法

将新结点插到头结点的后面,有两种形式,一是链表为空,二是链表中已有元素结点,如图

你可以分情况,不过也可以不用,例如:

bool insertLinkList(LinkList*& L, LinkNode *node) //node指向要添加的结点
{
	
	if (!L || !node) return false;

	node->next = L->next; //包含两种情况
	L->next = node;
	return true;
}

尾插法

尾插,顾名思义就是在最后一个结点插入之后,也分两种情况,一是链表为空,二是链表中已有元素结点,第一种情况的图和头插法的第一种情况的图一样,就是插入方式不同,以下是第二种情况的图:

我们只需要找到 next 指向 NULL 的这个结点就好了

bool LinkListinsert(LinkList*& L, LinkNode *node)
{
	if (!L || !node) return false;

	LinkNode* p = NULL;
	p = L;

	while (p->next != NULL) //如果是空链表,p == L,所以是包含两种情况
	{
		p = p->next;
	}
	
	node->next = p->next;
	p->next = node;

	return true;
}

指定位置插入

在第 i 个结点前插入,那么我们就必须有个临时指针指向第 i-1 个结点

bool InsertLink(LinkList*& L, int i, int e) // 这里也可以用之前的LinkNode *node参数,不过可能i不合法
{
	if (!L) return false;
	
	LinkNode* p = L , *s = NULL ;
	int j = 0;

	while (p && j < i - 1) // 指向第 i-1 个结点
	{	
		p = p->next;
		j++;
	}

	//如果在第0个位置之前插入(i<1) || 如果在最后一个结点+2的位置之前插入(i>n+1,n为链表长度)---都是非法的
	if (i < 1 || !p) return false;

	s = new LinkNode;
	s->date = e;
	s->next = p->next;
	p->next = s;
	return true;
}

遍历链表(打印链表)

bool PrintLinkList(LinkList *& L)
{
    if(!L) return false; 
	LinkNode* p = L->next; //首先指向第一个结点,如果为空链表就会指向 NULL

	while (p != NULL) // 直到指向最后一个结点的 next 指针(NULL)
	{
		printf("%d ", p->date);
		p = p->next;
	}
	cout << endl;
    return true;
}

遍历链表,也可以用来求链表的长度,代码与这个类似。

链表的获取

获取链表第 i 个结点的数据域。

bool GetElemLink(LinkList*& L, int i, int &e) //e返回获取的数据域
{

	LinkNode* p = L;
	int j = 0;

	while ( p!=NULL && j < i)
	{
		p = p->next;
		j++;
	}

	if (p==NULL || i < 1) //i是非法的:i > n(n为链表长度,例如:获取第n+1个结点的数据域)或者是 
 i < 1(例如:获取了第0个结点的数据域)
	{
		return false;
	}
	e = p->date;
	return true;
}

链表的查找

查找我们输入的元素在链表中出现的第一个位置。

bool FindElem(LinkList* L, int e,int &index) // index返回位置
{
	if (!L || !L->next) return false; //空链表

	LinkNode* p = L->next; // 现在指向第一个结点
	int j = 1;  

	while (p != NULL && p->date != e) 
	{
		p = p->next;
		j++;
	}

	if (p == NULL)
		return false;
	else
	{
		index = j;
		return true;
	}
}

链表的删除

删除第 i 个结点,i 可能不合法,注意不合法的原因。

bool DeleteLinkNode(LinkList*& L, int i)
{

	LinkNode* p = NULL , *q = NULL;

	p = L;

	int j = 0;
	while ( p->next!=NULL && j < i - 1)
	{
		p = p->next;
		j++;
	}
    // 指向第 i-1 个结点

	if (i < 1 || p->next == NULL) //i非法,删除第0个结点(i<1) 或者是 删除第n+1个结点(i>n,n为链表的长度)
		return false;
	else
	{
		q = p->next;
		p->next = q->next ;
		delete q;
		return true;
	}
	
}

链表的销毁(清空)

销毁就是要归还所申请的内存,删除某个结点时,一定要保存下一个结点的地址。简要解释:先保存第一个结点的地址,随后删除头结点(也申请了空间),再保存第二个结点的地址,删除第一个结点,再保存第三个结点……以此类推,可以将全部结点删除。

void DestoryLink(LinkList*& L)
{
	LinkNode* p = NULL, * q = NULL;

	p = L;

	while (p != NULL)
	{	
		q = p->next;
		//cout << "删除元素" << p->date << endl;
		delete p;
		p = q;
	}

}

总代码

以下是全部代码,链表的函数有不同的实现方法。也许我的代码和别人有些差异,所以可以看看 main 函数中是怎样的。

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>

using namespace std;


typedef struct _LinkNode
{
	int date;				//数据域
	struct _LinkNode* next; // 指针域

}LinkNode , LinkList;


//初始化链表
bool initLinkList(LinkList*& L)
{
	L = new LinkList;
	if (!L)
	{
		return false;
	}
	L->next = NULL;
	return true;
}

//前插法
bool insertLinkList(LinkList*& L, LinkNode *node)
{
	
	if (!L || !node) return false;

	node->next = L->next;
	L->next = node;
	return true;
}

//尾插法
bool LinkListinsert(LinkList*& L, LinkNode *node)
{
	if (!L || !node) return false;

	LinkNode* p = NULL;
	p = L;

	while (p->next != NULL)
	{
		p = p->next;
	}
	
	node->next = p->next;
	p->next = node;
	return true;
}

//在第i个结点前插入---指定位置插入
bool InsertLink(LinkList*& L, int i, int e)
{
	if (!L) return false;
	
	LinkNode* p = L , *s = NULL ;
	int j = 0;

	while (p && j < i - 1)
	{	
		p = p->next;
		j++;
	}

	//如果在第0个位置之前插入(i<1) || 如果在最后一个结点+2的位置之前插入(i>n+1,n为链表长度)---都是非法的
	if (i < 1 || !p) return false;

	s = new LinkNode;
	s->date = e;
	s->next = p->next;
	p->next = s;
	return true;
}

//打印链表
void PrintLinkList(LinkList *& L)
{
	LinkNode* p = L->next;

	while (p != NULL)
	{
		printf("%d ", p->date);
		p = p->next;
	}
	cout << endl;
}

//获取第i个结点的数据元素
bool GetElemLink(LinkList*& L, int i, int &e)
{

	LinkNode* p = L;
	int j = 0;

	while ( p!=NULL && j < i)
	{
		p = p->next;
		j++;
	}

	if (p==NULL || i < 1)
	{
		return false;
	}
	e = p->date;
	return true;
}

//在链表中查找元素,并且用index返回位置
bool FindElem(LinkList* L, int e,int &index)
{
	if (!L || !L->next) return false;

	LinkNode* p = L->next;
	int j = 1;

	while (p && p->date != e)
	{
		p = p->next;
		j++;
	}

	if (p == NULL)
		return false;
	else
	{
		index = j;
		return true;
	}
}


//删除第i个结点
bool DeleteLinkNode(LinkList*& L, int i)
{

	LinkNode* p = NULL , *q = NULL;

	p = L;

	int j = 0;
	while ( p->next!=NULL && j < i - 1)
	{
		p = p->next;
		j++;
	}


	if (i < 1 || p->next == NULL) //删除第0个结点(i<1) 或者是 删除第n+1个结点(i>n,n为链表的长度)
		return false;
	else
	{
		q = p->next;
		p->next = q->next ;
		delete q;
		return true;
	}
	
}


//清空(销毁)链表
void DestoryLink(LinkList*& L)
{
	LinkNode* p = NULL, * q = NULL;

	p = L;

	while (p != NULL)
	{	
		q = p->next;
		//cout << "删除元素" << p->date << endl;
		delete p;
		p = q;
	}

}
int main(void)
{
	LinkList* L = NULL; //指向表头(头结点)的指针
	LinkNode* e = NULL; //指向结点的指针
	initLinkList(L);

	int elem = 0;		//结点的数据元素
	int i;				//第几个结点
	int n = 0;			//输入的个数

	int flag = -1;
	while (flag != 0)
	{
		cout << "1.前插链表" << endl
			<< "2.尾插链表" << endl
			<< "3.指定位置前插入" << endl
			<< "4.打印链表" << endl
			<< "5.获取第i个结点的数据" << endl
			<< "6.查找元素" << endl
			<<"7.删除元素"<<endl
			<< "0.退出(销毁链表)" << endl;
		cout << "请选择:";
		cin >> flag;
		
		switch (flag)
		{
		case 1:
			cout << "请输入前插法插入链表的个数";
			cin >> n;
			cout << "请依次输入" << n << "个数:";
			while (n--)
			{
				e = new LinkNode;
				cin >> e->date;
				insertLinkList(L, e);
			}
			break;
		case 2:
			cout << "请输入尾插入链表的个数";
			cin >> n;
			cout << "请依次输入" << n << "个数:";
			while (n--)
			{
				e = new LinkNode;
				cin >> e->date;
				LinkListinsert(L, e);
			}
			break;
		case 3:
			cout << "请输入插入的位置和元素:";
			cin >> i >> elem;
			InsertLink(L, i, elem);
			break;
		case 4:
			PrintLinkList(L);
			break;
		case 5:
			cout << "请输入要获取的结点i:";
			cin >> i;
			if (GetElemLink(L, i, elem))
			{
				cout << "第" << i << "个结点的值为" << elem << endl;
			}
			else
			{
				cout << "获取元素失败" << endl;
			}
			break;
		case 6:
			cout << "请输入要查找的元素:";
			cin >> elem;
			if (FindElem(L, elem, i))
			{
				cout << "找到了,此元素的位置是" << i << endl;
			}
			else
			{
				cout << "表中无此值" << endl;
			}
			break;
		case 7:
			cout << "请输入要删除的结点i:";
			cin >> i;
			if (DeleteLinkNode(L, i))
			{
				cout << "删除成功" << endl;
			}
			else
			{
				cout << "删除失败" << endl;
			}
			break;
		case 0:
			DestoryLink(L);
			break;
		default:
			cout << "输入非法! " << endl;
			break;
		}



	}
	


	return 0;
}

这里也可以将代码复制,自己调试测试一下,删除某些代码,看看会有什么影响,更能理解。

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

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

相关文章

存档&改造【06】Apex-Fancy-Tree-Select花式树的使用误删页数据还原(根据时间节点导出导入)

之前一直想实现厂区-区域-产线之间的级联选取&#xff0c;于是导入插件Apex-Fancy-Tree-Select花式树 存档&#xff06;改造【03】Apex-Fancy-Tree-Select花式树的导入-CSDN博客 现在则是在Oracle Apex中的应用 花式书级联列表展示厂区-区域-产线 想要实现的效果 由厂区>…

Shopee活动报错怎么办?Shopee活动类型怎么选择?-站斧浏览器

有时候&#xff0c;在同步虾皮活动的过程中&#xff0c;您可能会遇到一些问题或报错信息。遇到这种情况要怎么办&#xff0c;Shopee活动类型怎么选择&#xff1f; Shopee活动报错怎么办&#xff1f; 下面是几种常见的问题及其解决方法&#xff1a; 1、网络连接问题&#xff…

05 | @Query 解决了什么问题?什么时候应该选择它?

上个课时我们介绍了 Query Define Method 的语法&#xff0c;这一课时来介绍一下 Query 注解的语法是什么样的。我们通过快速体验 Query 的方法、JpaQueryLookupStrategy 关键源码剖析、Query 的基本用法、Query 之 Projections 应用返回指定 DTO、Query 动态查询解决方法&…

网工笔记整理:策略工具Filter-policy的使用

一、概述 Filter-Policy&#xff08;过滤-策略&#xff09;是一个很常用的路由信息过滤工具&#xff0c;能够对接收、发布、引入的路由进行过滤&#xff0c;可应用于IS-IS、OSPF、BGP等协议。 Filter-policy在距离矢量路由协议中的应用 filter-policy import&#xff1a;不发…

Python学习基础笔记六十五——布尔值

布尔对象&#xff1a; Python中有一种对象类型称之为布尔对象&#xff08;英文叫bool&#xff09;。 布尔对象只有两种取值&#xff0c;True和False。对应的是真和假&#xff0c;或者说是和否。True对应的是&#xff0c;False对应的是否。 我觉得这句话是一个关键&#xff1a…

04 | 如何利用 Repository 中的方法返回值解决实际问题?

上一课时&#xff0c;我们着重讲了方法名和参数的使用方法&#xff0c;这一课时我们来看下Repository 支持的返回结果有哪些&#xff0c;以及 DTO 类型的返回结果如何自定义&#xff0c;及其在实际工作场景中我们如何做。通过本课时的学习&#xff0c;你将了解到 Repository 的…

Ansible概述以及模块

目录 一、Ansible概述 1、Ansible是什么 2、Ansible的作用 3、Ansible的特性 4、Ansible的工作机制 5、Ansible的特点 二、Ansible安装部署 1、管理端安装ansible 2、配置主机清单 3、配置密钥对验证 三、Absible命令行模块 1、command模块 2、shell模块 3、cron …

Jackson+Feign反序列化问题排查

概述 本文记录在使用Spring Cloud微服务开发时遇到的一个反序列化问题&#xff0c;RPC/HTTP框架使用的是Feign&#xff0c;JSON序列化反序列化工具是Jackson。 问题 测试环境的ELK告警日志如下&#xff1a; - [43f42bf7] 500 Server Error for HTTP POST "/api/open/d…

一篇文章让你了解“JWT“

一.JWT简介 1.概念 JWT (JSON Web Token) 是一种用于在网络上安全传输信息的开放标准&#xff08;RFC 7519&#xff09;。它是一种紧凑且自包含的方式&#xff0c;用于在不同组件之间传递信息&#xff0c;通常用于身份验证和授权目的。JWT 是以 JSON 格式编码的令牌&#xff…

Shell后门脚本

说明&#xff1a;请在云服务器中执行&#xff0c;执行脚本后会发生 1、创建${create_user}用户并赋予sudo权限2、获取公网IP地址和SSH端口3、将用户公网IPSSH端口信息发送给${mail_from}变量 #!/bin/bash # 收件人邮箱 mail_fromxxxxx.com sshd_port$(grep "^Port"…

AI低代码维格云甘特视图怎么用?

甘特视图,以日期为横轴展示任务持续时长和先后顺序,简称甘特图。 项目管理过程中,合理分配任务和资源至关重要,使用甘特图,妥当解决以下场景: 想知道整个项目的周期多长,哪些任务对项目的周期影响最大; 想知道每个任务的时间有多长,任务的优先级和依赖关系是什么; 想…

VUE3页面截取部署后的二级目录地址

用vue3开发了一个项目&#xff0c;只能部署在根目录&#xff0c;不能加二级目录&#xff0c;后来网上找了解决方案&#xff0c;在vite.config.ts中增加base: ./,配置解决问题&#xff0c;参考下图&#xff1a; 但部署后要获取部署的二级目录地址切遇到问题&#xff0c;后来想了…

SQL如何导入数据以及第一次上机作业

如何导入excel数据 首先得学会导入数据 使用excel格式不需要改成其它格式&#xff08;如csv&#xff0c;txt&#xff09;&#xff0c;因为你改了到时候还是会报错&#xff08;实践过使用Sum统计总数一直说我数据格式有问题&#xff09; 首先右键TSGL数据库->任务->导入数…

makefile规则查找

文章目录 对应 跟我一起写Makefile2.1**makefile** **的规则****2.2** **一个示例****2.5** **让** **make** **自动推导****2.6 makefile** **的另一种风格****2.7** **清空目录的规则****2.10** **包含其它** **Makefile****3.4** **文件搜寻****3.5** **伪目标****3.6** **多…

AWS香港Web3方案日,防御云安全实践案例受关注

9月26日&#xff0c;AWS合作伙伴之Web3解决方案日在香港举办。来自人工智能、Web3等领域的创业公司、技术专家、风险投资商&#xff0c;就元宇宙时代未来发展进行了深入交流。现场展示了顶象防御云在金融与Web3领域的安全实践案例。 Web3为互联网体系架构的一个整体演进和升级&…

LoRa技术未来发展前景:物联网和边缘计算的引领者

随着物联网和边缘计算的快速发展&#xff0c;低功耗广域网&#xff08;LoRa&#xff09;技术在连接远距离设备、实现长距离通信和满足低功耗需求方面崭露头角。本文将分析LoRa技术在未来的发展前景&#xff0c;尤其是在物联网和边缘计算领域的潜在影响。 LoRa技术的核心优势 1…

自动化产线集控系统(西门子CNC 840D/840DSL远程控制)

1.1项目背景 RQQ/VF120机组目前为1人操作3台机床&#xff0c;需在机台旁监控。为了改善人员在班中劳动强度非常大的现状&#xff0c;调整好每台机床的节奏&#xff0c;以保证机床的最少的等待时间。本项目旨在通过远程监视设备运行过程关键参数&#xff0c;操作人员人员可远程监…

清洁洗鞋商城小程序的作用是什么

人靠衣装&#xff0c;一身干净合身的衣物总是给人赏心悦目的感觉&#xff0c;人们对颜值要求越来越高&#xff0c;不仅是衣服&#xff0c;鞋也是重要的组成部分。各种品牌样式鞋&#xff0c;很多人家里往往有几十双&#xff0c;而在清洁这一块&#xff0c;没有时间、或材质特殊…

JS加密/解密之webpack打包代码逆向

Webpack 是一个强大的打包工具&#xff0c;能够将多个文件打包成一个或多个最终的文件。然而&#xff0c;将已经经过打包的代码还原回原始源代码并不是一件直接的事情&#xff0c;因为 webpack 打包的过程通常会对代码进行压缩、混淆和优化&#xff0c;丢失了部分变量名和代码结…

K8S环境搭建

K8S环境搭建 前置条件 部署3台VM&#xff0c;一台作为master,两台作为slave需要保障vm之间网络是互通的 为vm安装docker # 安装/更新 yum-utils yum install -y yum-utils#添加阿里镜像稳定版仓库 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce…