链表(7.27)

news2024/11/18 21:41:41
3.3 链表的实现
3.3.1头插
原理图:
newnode为新创建的节点
实现:
//头插
//让新节点指向原来的头指针(节点),即新节点位于开头
newnode->next = plist;
//再让头指针(节点)指向新节点,新节点就成为了头节点
plist = newnode;

此操作在链表为空的情况下也能正常运行。

3.3.2尾插
原理:创建一个新节点,先通过局部变量 tail 遍历找到指向的下一个节点为空的节点(即倒数第二个节点),然后将该节点与新节点链接起来。
初步实现:
// 单链表尾插
//第一个参数为头指针的拷贝(形参)
void SListPushBack(SLTNode* phead, SLTDataType x)
{
	SLTNode* tail = phead;
	//创建要插入的新节点
	SLTNode* newnode = BuySListNode(x);
	//遍历下一个节点指向为空的节点
	while (tail->next != NULL)
	{
		tail = tail->next;
	}
    //将该节点与新节点链接起来
	tail->next = newnode;
}

phead,tail,newnode为局部变量,出了作用域就会自动销毁,而链表的节点存在于堆上,不会自动销毁。

上面的步骤是在原有链表的前提下进行的,如果链表为空呢?

需要让新节点充当头节点,也就是要让 plist(结构体指针)(头指针) 指向新节点,因此我们尝试将新创建的节点赋给头指针

if (phead == NULL)
	{
		phead = newnode;
	}

但这个做法对吗,显然不对,形参是实参的一份临时拷贝,改变形参不影响实参,出了这个作用域,这两个指针就销毁了,plist也没有改变。

plist 是结构体类型的指针,要改变它的值,在函数中就需要传它的地址,也就是指针的地址。

//第一个参数为头指针的拷贝(形参)
void SListPushBack(SLTNode** pphead, SLTDataType x)
{
    SLTNode* newnode = BuySListNode(x);
	//如果链表为空
	//*pphead==plist
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		//创建要插入的新节点

		//遍历下一个节点指向为空的节点
		while (tail->next != NULL)
		{
			tail = tail->next;
		}//将该节点与新节点链接起来
		tail->next = newnode;
	}
}

 总结:

改变结构体用结构体指针;

改变结构体指针用结构体二级指针;

3.3.3头插

本篇开头已经在函数外实现过了,现在在函数中实现一次。

每一次头插都要改变 plist 头指针,因此也需要传二重指针

// 单链表的头插
void SListPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySListNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

3.3.4尾删

根据剩余节点的不同,分3种情况

1.链表为空

这是一种异常的情况,我们需要使用断言对参数加以限制,以防传空指针情况的出现。

assert(*pphead);

2.链表只剩一个节点

再删掉就为空,这时候就需要释放节点的空间,并将头指针置空,就涉及到了头指针的改变,需要引用二级指针。

    if ((*pphead)->next == NULL)
    {
        free(*pphead);
        *pphead = NULL;
    }

3.链表中包含>1个节点

用 tail 找到末尾节点并将其删除,将倒数第二个节点置空,该情况下不需要二级指针。

原理图:

SLTNode* tailPre = NULL;
        SLTNode* tail = *pphead;
        while (tail->next != NULL)
        {
            tailPre = tail;
            tail = tail->next;
        }
        free(tail);
        tailPre->next = NULL;

3.3.5头删

让头指针指向第二个节点,将第一个节点释放。

// 单链表头删
void SListPopFront(SLTNode** pphead)
{
	assert(*pphead);
	//第二个节点
	SLTNode* newhead = (*pphead)->next;
	//释放第一个节点
	free(*pphead);
	//让第二个节点成为新的头节点
	*pphead = newhead;
}

完整代码:

头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;
//打印链表
void SLTPrint(SLTNode* pahead);
//开辟一个节点并赋值
SLTNode* BuySLTNode(SLTDataType X);
// 单链表尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
// 单链表的头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
// 单链表的尾删
void SLTPopBack(SLTNode** pphead);
// 单链表头删
void SLTPopFront(SLTNode** pphead);

 测试文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
void TestSList1()
{
	int n = 0;
	printf("请输入链表的长度\n");
	scanf("%d", &n);
	printf("请依次输入每个节点的值\n");
	//创建头指针
	SLTNode* plist = NULL;
	for (int i = 0; i < n; i++)
	{
		int val = 0;
		scanf("%d", &val);
		//开辟新节点
		SLTNode* newnode = BuySLTNode(val);

		//头插
		//让新节点指向原来的头指针(节点),即新节点位于开头
		newnode->next = plist;
		//再让头指针(节点)指向新节点,新节点就成为了头节点
		plist = newnode;
	}
	SLTPushBack(&plist, 100);
	SLTPrint(plist);
}
void TestSList2()
{
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);
}
void TestSList3()
{
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);


	SLTPopBack(&plist);
	SLTPrint(plist);

	SLTPopBack(&plist);
	SLTPrint(plist);

	SLTPopBack(&plist);
	SLTPrint(plist);

	SLTPopBack(&plist);
	SLTPrint(plist);

	SLTPopBack(&plist);
	SLTPrint(plist);

	// SLTPopBack(&plist);
	// SLTPrint(plist);
}
void TestSList4()
{
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPushBack(&plist, 5);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTPopFront(&plist);
	//SLTPopFront(&plist);
	SLTPrint(plist);
}
//void TestSList5()
//{
//	SLTNode* plist = NULL;
//	SLTPushBack(&plist, 1);
//	SLTPushBack(&plist, 2);
//	SLTPushBack(&plist, 3);
//	SLTPushBack(&plist, 4);
//	SLTPushBack(&plist, 5);
//	SLTPrint(plist);
//
//	SLTNode* pos = SLTFind(plist, 3);
//	SLTInsert(&plist, pos, 30);
//}
int main()
{
	//TestSList1();
	TestSList2();
	/*TestSList3();
	TestSList4();
	TestSList5();*/
	return 0;
}

实现文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	//结束,打印空
	printf("NULL\n");
}
//开辟节点并赋值
SLTNode* BuySLTNode(SLTDataType X)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	newnode->data = X;
	newnode->next = NULL;

	return newnode;
}
// 单链表尾插
//第一个参数为头指针的拷贝(形参)
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
    SLTNode* newnode = BuySLTNode(x);
	//如果链表为空
	//*pphead==plist
	if (*pphead == NULL)
	{
		//改变结构体指针,用结构体二级指针
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		//创建要插入的新节点

		//遍历下一个节点指向为空的节点
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		//改变结构体用结构体指针,将该节点与新节点链接起来
		tail->next = newnode;
	}
}
// 单链表的头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuySLTNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}
// 单链表的尾删
void SLTPopBack(SLTNode** pphead)
{
	//限制参数不为空
	assert(*pphead);
	//仅有一个节点的情况
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//有两个及以上节点的情况
	else
	{
		//尾节点的前一个节点
		SLTNode* tailPre = NULL;
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tailPre = tail;
			//tail往后走之前赋给前一个指针
			tail = tail->next;
		}
		free(tail);
		tailPre->next = NULL;
	}
}
// 单链表头删
void SLTPopFront(SLTNode** pphead)
{
	assert(*pphead);
	//第二个节点
	SLTNode* newhead = (*pphead)->next;
	//释放第一个节点
	free(*pphead);
	//让第二个节点成为新的头节点
	*pphead = newhead;
}

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

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

相关文章

【亲测】简易商城小程序源码-易优CMS后台

易优小程序是基于前端开源小程序后端易优CMS标签化API接口&#xff0c; 是一套开源、快速搭建个性化需求的小程序CMS。轻量级TP底层框架&#xff0c;前后端分离&#xff0c; 标签化API接口可对接所有小程序&#xff0c;支持二次开发。即使小白用户也能轻松搭建制作一套完整的线…

90后整顿秦始皇老板

我的日常就像跑步机上急速前行的仓鼠&#xff0c;使劲往前冲&#xff0c;心有余力力有限。 我在一个电商运营公司做策划和写文案&#xff0c;每天总是加不完的班&#xff0c;从来没见过下午六点钟的太阳。 我做文案吗&#xff1f;唉&#xff0c;说实话&#xff0c;我倒觉得大…

C#(Csharp)我的基础教程(二)(我的菜鸟教程笔记)-属性和字段的探究与学习

目录 1、字段字段特点&#xff1a;2、属性属性的特点 1、字段 字段是定义在方法外面的变量&#xff0c;是成员变量&#xff0c;主要是为了类的内部数据交换使用&#xff0c;字段一般是用private修饰&#xff0c;也可以用readonly修饰&#xff0c;表示只读字段&#xff0c;其它…

10月底下架!亚马逊新增5大售前审核品类,提醒这6大站点卖家注意

近期&#xff0c;不少加拿大站、沙特阿拉伯站、埃及站、瑞典站、波兰站以及比利时站卖家陆续收到了亚马逊合规政策要求邮件&#xff0c;包括加拿大站对于“带拉绳的童装”、“水壶”、“玻璃门和围栏”三个品类&#xff0c;沙特阿拉伯、埃及对于“面向婴幼儿的食品”品类&#…

如何在C++项目中用C#运行程序调试C++ DLL

问题描述 在C#项目中调用C DLL时报错或者运行结果不符&#xff0c;此时需要运行C#项目并在C中加入断点进行调试 项目准备 项目一&#xff1a;C#项目&#xff08;该项目调用C DLL&#xff09;项目二&#xff1a;C项目&#xff08;生成C DLL&#xff09; 这两个项目不需要在同…

BGP服务器租用腾讯云和阿里云价格对比

BGP云服务器像阿里云和腾讯云均是BGP多线网络&#xff0c;速度更快延迟更低&#xff0c;阿里云BGP服务器2核2G3M带宽优惠价格108元一年起&#xff0c;腾讯云BGP服务器2核2G3M带宽95元一年起&#xff0c;阿腾云atengyun.com分享更多云服务器配置如2核4G、4核8G、8核16G等配置价格…

VALSE2023-快速总结

会议快速总结 1. 前言2. 热点词2.1 自监督预训练2.2 MIM(Masked Image Modeling)2.3 MAE(Masked Autoencoders)2.4 clip&#xff08;Contrastive Language-Image Pre-Training&#xff09;模型2.5 对比学习2.6 扩散模型&#xff08;diffustion model&#xff09;2.7 Nerf&#…

超高速PCIe实时运动控制卡与应用方案将亮相深圳NEPCON,正运动技术邀您前来体验!

助力电子半导体设备加速国产替代导入&#xff0c;正运动超高速PCIe运动控制卡可覆盖电子半导体大部分工艺流程应用&#xff0c;提供高速高精稳定的运动控制解决方案。 ■展会名称&#xff1a; NEPCON ASIA 2023亚洲电子生产设备暨微电子工业展&#xff08;以下简称“2023亚洲…

c#设计模式-行为型模式 之 中介者模式

&#x1f680;简介 又叫调停模式&#xff0c;定义一个中介角色来封装一系列对象之间的交互&#xff0c;使原有对象之间的耦合松散&#xff0c;且可以独立地改变它们之间的交互。 从下右图中可以看到&#xff0c;任何一个类的变 动&#xff0c;只会影响的类本身&#xff0c;以及…

TikTok震撼全球!用户来自何方?

TikTok&#xff08;抖音国际版&#xff09;作为一款风靡全球的短视频应用&#xff0c;正以惊人的速度改变着人们的娱乐方式、社交习惯和消费行为。它汇聚了来自不同地域、不同文化背景的用户&#xff0c;形成了一个庞大而多样化的社区。 这个社区的形成和发展&#xff0c;让我…

TikTok Shop:年轻一代购物革命的未来之旅

随着社交媒体的不断崛起&#xff0c;我们的生活方式也在发生深刻的变革。在这个数字化时代&#xff0c;年轻一代的文化和消费习惯正在不断演变&#xff0c;而TikTok Shop正是这场购物革命的先锋。 一、TikTok Shop的崛起 TikTok Shop是TikTok平台上的一项新功能&#xff0c;旨在…

Vue3中使用tinymce全功能演示,包括开源功能

效果图&#xff1a; 1、下载插件: npm i tinymce npm i tinymce/tinymce-vue 2、在node_modules文件夹中找到tinymce下的skins复制到项目public文件夹中 &#xff08;可以先创建一个tinymce文件夹&#xff09;&#xff1a; 3、在tinymce官网中下载中文包&#xff0c;并放在刚…

天锐绿盾加密软件——企业数据防泄密-CAD图纸、文档、源代码加密管理系统@德人合科技

天锐绿盾是一款专门为企业提供数据防泄密和文档加密管理的软件。该软件通过加密技术保护企业的核心数据&#xff0c;防止数据泄露和侵权行为&#xff0c;同时提供了全方位的文档加密管理系统&#xff0c;实现了对企业数据的安全保障和有效管理。 PC访问地址&#xff1a; isite…

使用安卓Termux+Hexo,手机也能轻松搭建个人博客网站

文章目录 前言1.安装 Hexo2.安装cpolar3.远程访问4.固定公网地址5.结语 前言 Hexo 是一个用 Nodejs 编写的快速、简洁且高效的博客框架。Hexo 使用 Markdown 解析文章&#xff0c;在几秒内&#xff0c;即可利用靓丽的主题生成静态网页。 下面介绍在Termux中安装个人hexo博客并…

Redis-01基本数据结构

1、String 1.1、介绍 String 是最基本的 key-value 结构&#xff0c;key 是唯一标识&#xff0c;value 是具体的值&#xff0c;value其实不仅是字符串&#xff0c; 也可以是数字&#xff08;整数或浮点数&#xff09;&#xff0c;value 最多可以容纳的数据长度是 512M 1.2、…

KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(1)

序言 最近在研究libdrm、DRM以及KWin&#xff0c;发现要真正理解Linux图形栈从上到下的机制&#xff0c;最好的、最易于理解的方法是将KWin、libdrm和DRM由上到下的调用过程暨代码统一进行研究&#xff0c;这样才能更好地理清其中的关系&#xff0c;把握总体全貌&#xff0c;因…

【WebService】C#搭建的标准WebService接口,在使ESB模版作为参数无法获取参数数据

一、问题说明 1.1 问题描述 使用C# 搭建WebService接口&#xff0c;并按照ESB平台人员的要求&#xff0c;将命名空间改为"http://esb.webservice",使用PostmanESB平台人员提供的入参示例进行测试时&#xff0c;callBussiness接口参数message始终为null。 以下是ES…

实验2.1.1 交换机的管理方式

实验2.1.1 交换机的管理方式 一、具体要求二、实验拓扑三、任务实施1.在PC机中使用默然参数连接交换机。3.通过system-view命令进入系统视图4.使用sysname重命名交换机为SWA。5.使用display current-configuration 命令查看交换机的配置信息。6.使用save命令保存配置信息。 一、…

35 WEB漏洞-逻辑越权之找回机制及接口安全

目录 找回重置机制接口调用乱用演示案例绑定手机验证码逻辑-Rep状态值篡改-实例某APP短信轰炸接口乱用-实例接口调用发包 文章分享&#xff1a;https://www.cnblogs.com/zhengna/p/15655691.html 有支付接口、短信发送接口&#xff0c;邮箱的发送接口等等&#xff0c;在接口这…