【数据结构】单链表中,如何实现 将链表中所有结点的链接方向“原地”逆转

news2024/11/24 16:37:21

一.实现一个单链表(无头单向不循环)

我们首先实现一个无头单向不循环单链表。

写出基本的增删查改功能,以及其它的一些功能(可忽略)。

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

SLTNode* BuyListNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		printf("malloc failed.\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
}

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

void SListPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyListNode(x);

	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		//找到尾结点
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}
}

void SListPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyListNode(x);

	newnode->next = *pphead;
	*pphead = newnode;
}

void SListPopBack(SLTNode** pphead)
{
	assert(*pphead != NULL);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* tail = *pphead;
		SLTNode* prev = NULL;
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;

		prev->next = NULL;
	}
}

void SListPopFront(SLTNode** pphead)
{
	assert(*pphead);
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return NULL;
}

void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	SLTNode* newnode = BuyListNode(x);
	if (*pphead == pos)
	{
		newnode->next = *pphead;
		*pphead = newnode;
	}
	else
	{
		SLTNode* posPrev = *pphead;
		while (posPrev->next != pos)
		{
			posPrev = posPrev->next;
		}

		posPrev->next = newnode;
		newnode->next = pos;

	}
}

void SListErase(SLTNode** pphead, SLTNode* pos)
{
	if (*pphead == pos)
	{
		*pphead = pos->next;
		free(pos);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}

void SListDestroy(SLTNode** pphead)
{
	assert(*pphead);
	SLTNode* cur = *pphead;
	SLTNode* next = (*pphead)->next;
	while (next)
	{
		free(cur);
		cur = next;
		next = next->next;
	}
	free(cur);
	*pphead = NULL;
}

//通过一趟遍历确定长度为n的单链表中值最大的结点
SLTNode* SListFindMax(SLTNode* pphead)
{
	assert(pphead);
	SLTNode* cur = pphead;
	SLTNode* maxnode = pphead;
	SLTDataType max = pphead->data;
	while (cur)
	{
		if (cur->data > max)
		{
			max = cur->data;
			maxnode = cur;
		}
		cur = cur->next;
	}
	return maxnode;
}

二.原地逆转

接下来我们要写一个接口,实现:将链表中所有结点的链接方向“原地”逆转,即要求仅利用原表的存储空间,换句话说,要求空间复杂度为O(1)

那么,我们需要将链表遍历,进行逆转,改变链接方向 时,要尤其注意,避免行差踏错。

//将链表中所有结点的链接方向“原地”逆转,即要求仅利用原表的存储空间,换句话说,要求空间复杂度为O(1)
void SListReverse(SLTNode** pphead) 
{
	SLTNode* head = *pphead;   //此指针在每次循环中始终指向当前链表的头
	SLTNode* tmp = head->next; //此指针在每次循环中始终指向要被后删头插的节点
	SLTNode* oldhead = *pphead;   //此指针在每次循环中始终指向原本的头结点,不会改变指向
	while (tmp) //如果tmp为空,则代表逆序结束,旧头的next已经是空的了,成为新链表的末尾
	{
		oldhead->next = tmp->next; //将tmp架空,实际是后删操作的一部分
		tmp->next = head; //让tmp变成新的头,实际是头插操作的一部分 
		head = tmp; //换头
		tmp = oldhead->next; //让tmp变成下次循环中待删除的节点
	}
	*pphead = head;
}

或许仅仅一段代码不足以让你理解,我们可以来看下面的图。

对照着代码,每一次循环就是下面的一行。

最后一行即为逆转后的链表。

 

 三.测试运行

最后,我们来看一下上面代码的运行效果。

我们可以写一个测试函数。

void TestSList()
{
	SLTNode* plist = NULL;
	SListPushBack(&plist, 1);
	SListPushBack(&plist, 2);
	SListPushBack(&plist, 3);
	SListPushBack(&plist, 4);
	SListPushBack(&plist, 5);
	SListPrint(plist);

	SListReverse(&plist);
	SListPrint(plist);

	SListDestroy(&plist);

}

int main()
{

	TestSList();

	return 0;
}

运行结果

这样,我们就实现了链表的原地逆转。 

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

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

相关文章

ros使用详解

文章目录ros概述ros使用winbox登录ros关机重启ros修改路由器名ros恢复出厂设置ros修改管理员账号密码及限制登录IPros备份还原ros使用pppor拨号ros的nat&#xff0c;也叫伪装ros静态ARP绑定ros端口映射ros配置静态路由ros概述 软路由是指利用台式机或服务器的供应商配合一定软…

mos管驱动与米勒平台介绍、消除

mos驱动设计 1.选择适当的驱动芯片 为了控制MOSFET&#xff0c;需要使用专门的驱动芯片。选择合适的芯片需要考虑MOSFET的电压和电流需求。常见的驱动芯片包括IR2110、IR2184、MIC4424等。 2.设计电路 在驱动电路中&#xff0c;需要加入一些电路元件来保证MOSFET的顺畅工作…

爱国者一体机电脑蓝屏怎么U盘重装系统教学?

爱国者一体机电脑蓝屏怎么U盘重装系统教学&#xff1f;有用户使用的爱国者一体机电脑开机了之后突然变成了蓝屏的了。而且无法继续使用了&#xff0c;那么遇到这样的蓝屏问题怎么去进行系统的重装呢&#xff1f;一起来看看以下的U盘重装系统教学吧。 准备工作&#xff1a; 1、U…

es6动态模块import()

目录 一、语法说明 二、适用场合 三、注意点 四、示例代码 五、效果 一、语法说明 import命令会被 JavaScript 引擎静态分析&#xff0c;先于模块内的其他语句执行&#xff08;import命令叫做“连接” binding 其实更合适&#xff09;。 // 报错 if (x 2) {import MyMod…

网络安全工程师在面试安全岗位时,哪些内容是加分项?

金三银四已经来了&#xff0c;很多小伙伴都在困惑&#xff0c;面试网络安全工程师的时候&#xff0c;有哪些技能是加分项呢&#xff1f;接下来&#xff0c;我简单说说&#xff01; 去年我在微博上贴了一些在面试安全工作时会加分的内容&#xff0c;如下&#xff1a; 1. wooyu…

MySQL、HBase、ElasticSearch三者对比

1、概念介绍 MySQL&#xff1a;关系型数据库&#xff0c;主要面向OLTP&#xff0c;支持事务&#xff0c;支持二级索引&#xff0c;支持sql&#xff0c;支持主从、Group Replication架构模型&#xff08;本文全部以Innodb为例&#xff0c;不涉及别的存储引擎&#xff09;。 HBas…

【AI JUST AI】自然语言交互式学习,ChatGPT成了我的最佳博客写作助手

【AI JUST AI】自然语言交互式学习&#xff0c;ChatGPT成了我的最佳博客写作助手什么是自然语言交互式学习&#xff1f;ChatGPT是如何成为我的最佳博客写作助手的&#xff1f;**把与Chat GPT的每一次对话都当作一种类型的非系统学习**有问必答&#xff0c;随时交互总结后记——…

【Python】案例介绍Pytest进行压力测试

在现代Web应用程序中&#xff0c;性能是至关重要的。为了确保应用程序能够在高负载下正常运行&#xff0c;我们需要进行性能测试。 今天&#xff0c;应小伙伴的提问&#xff0c; 田辛老师来写一个Pytest进行压力测试的简单案例。 这个案例的测试网站我们就隐藏了&#xff0c;不…

Windows 10 - Python 消息队列 RabbitMQ 学习总结 1

目录消息队列的基本知识概述什么是消息队列&#xff1f;为何要使用消息队列的原因&#xff1f;理解消息队列服务器和 Web 服务器的关系题外&#xff1a;关于服务端和客户端的企业级理解了解 Web 服务器了解 Web 框架和 Web 服务的区别对于框架和服务器B/S架构消息队列的个人理解…

PMP项目管理项目风险管理

目录1 项目风险管理概述2 规划风险管理3 识别风险4 实施定性风险分析5 实施定量风险分析6 规划风险应对7 实施风险应对8 监督风险1 项目风险管理概述 项目风险管理的目标在于提高正面风险的概率和&#xff08;或&#xff09;影响&#xff0c;降低负面风险的概率和&#xff08;…

STM32CubeIDE 快速开发入门指南

描述 STM32CubeIDE是一体式多操作系统开发工具&#xff0c;是STM32Cube软件生态系统的一部分。 STM32CubeIDE是一种高级C/C开发平台&#xff0c;具有STM32微控制器和微处理器的外设配置、代码生成、代码编译和调试功能。它基于Eclipse/CDT™框架和用于开发的GCC工具链&#xf…

CentOS7部署Doris V1.2.2

一、环境准备 服务器信息 IP配置部署内容192.168.43.1508核8GFE&#xff0c;BE192.168.43.1514核8GBE192.168.43.1524核8GBE 安装前置条件 服务器配置免密登录 3台服务器配置免密登录&#xff0c;可参考CentOS7 设置SSH免密钥登陆 安装JDK 安装JDK 修改CentOS系统默认参…

【opensea】opensea-js 升级导致的问题,及解决笔记

opensea 协议升级导致旧包不能使用了 我使用的是 “opensea-js”: "^4.0.12” 版本当SDK。于2023年3月9日之后&#xff0c;不能使用了&#xff0c;需要升级到 Seaport v1.4 协议的包。 报错如下: Error: API Error 400: Please provide an OPEN order type when using …

第N次重装系统之Ubtntu

前言又一次换了服务器&#xff0c;由于centOS已经完成了自己的生命周期&#xff0c;接下来我会转去使用Ubtntu系统。当然&#xff0c;大部分docker命令是不会收到影响的&#xff0c;但是一部分安装过程可能就要重新学习了。其实这个系统也有自己的老牌包管理器apt&#xff0c;所…

ESP32设备驱动-TCS3200颜色传感器驱动

TCS3200颜色传感器驱动 1、TCS3200介绍 TCS3200 和 TCS3210 可编程彩色光频率转换器在单个单片 CMOS 集成电路上结合了可配置的硅光电二极管和电流频率转换器。 输出是方波(50% 占空比),其频率与光强度(辐照度)成正比。 满量程输出频率可以通过两个控制输入引脚按三个预…

关系抽取方面的基础

关系抽取方面的基础一、基本概念1. 什么是关系抽取&#xff08;Relation Extraction&#xff0c;RE&#xff09;&#xff1f;2. 都有什么奇怪的关系&#xff1f;3. 任务评价指标二、 关系抽取方法2.1 按模型结构分——Pipeline 和 Joint方法Pipeline方法Joint方法2.2 按解码方式…

RK3588平台开发系列讲解(同步与互斥篇)信号量介绍

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、信号量介绍二、信号量API1、结构体2、API三、函数调用流程沉淀、分享、成长,让自己和他人都能有所收获!😄 📢上一章我们看了自旋锁的原理,本章我们一起学习下信号量的用法。 一、信号量介绍 和自旋锁一样,…

计算机网络:IP组播

IP数据报的三种传输方式 单播&#xff1a;将数据包发送到单个目的地址&#xff0c;且每发送一份单播报文都是使用一个单播IP地址作为目的地址&#xff0c;是一种点对点协议。广播&#xff1a;将数据包发送给同一广播域或者子网内所有设备的通信方式&#xff0c;是一种点对多点…

javaEE 初阶 — CSS 的 基本语法 与 引入方式

文章目录1. 基本语法规范2. 三种引入方式1. 基本语法规范 CSS 的基本语法规范是由 选择器 和 若干个声明 组成的。 选择器选中一个元素之后&#xff0c;这些属性都是针对于这个元素展开的。 先来看一个没有 CSS 的效果。 <body><p>这是一个段落</p> </bo…

超详细!工业级RK3568核心板性能测试与压力测试记录

1. 测试对象HD-RK3568-IOT底板是基于HD-RK3568-CORE工业级核心板设计的&#xff0c;具有双网口、双CAN、5路串口等丰富接口&#xff0c;适用于工业现场应用需求&#xff0c;方便用户评估核心板及CPU性能&#xff0c;可用于工业自动化控制、人机界面、医疗分析器、电力等多种行业…