【C语言】数据结构——无头单链表实例探究

💗个人主页💗
⭐个人专栏——数据结构学习⭐
💫点击关注🤩一起学习C语言💯💫

目录

  • 导读:
  • 1. 单链表
    • 1.1 什么是单链表
    • 1.2 优缺点
  • 2. 实现单链表基本功能
    • 2.1 定义结构体
    • 2.2 单链表打印
    • 2.3 销毁单链表
    • 2.4 动态申请一个结点
    • 2.5 单链表尾插
    • 2.6 单链表尾删
    • 2.7 单链表头插
    • 2.8 单链表头删
    • 2.9 单链表查找
    • 2.10 单链表任意插入
    • 2.11 单链表任意删除
  • 3. 代码整理
    • 3.1 SList.h声明函数
    • 3.2 SList.c定义函数
    • 3.3 study.c调用
  • 4. 博主有话说

导读:

在前面我们已经学习了顺序表,今天我们来学习链表的单链表,也是无头的单链表,这需要对一级指针和二级指针有充分的了解。

1. 单链表

1.1 什么是单链表

单链表是一种常见的数据结构,由一系列节点依次连接形成。
每个节点包含两部分信息:数据信息指向下一个节点的指针
单链表的第一个节点称为头节点,最后一个节点没有下一个节点,其指针指向空。
类似于火车,火车头连接后一个车厢,再由后面的车厢依次连接
在这里插入图片描述

图1.1

1.2 优缺点

单链表的优点:

  1. 动态性:单链表的长度可以动态增长,不需要预先指定长度;
  2. 内存利用率高:链表中每个节点只需要存储下一个节点的地址,不需要像数组那样存储固定大小的位置,因此可以更加灵活地利用内存;
  3. 插入和删除操作方便:由于只需要改变链表节点中的指针,可以很方便地在链表中插入和删除节点。

单链表的缺点:

  1. 随机访问困难:由于必须从头节点开始遍历整个链表才能访问任意位置上的节点,因此随机访问效率较低;
  2. 存储空间浪费:由于链表节点中需要保存指向下一个节点的指针,因此需要额外的存储空间;
  3. 不支持反向遍历:由于链表节点只存储了指向下一个节点的指针,因此无法反向遍历链表。

2. 实现单链表基本功能

我们需要创建两个 C文件: study.c 和 SList.c,以及一个 头文件: SList.h。
头文件来声明函数,一个C文件来定义函数,另外一个C文件来用于主函数main()进行测试。

2.1 定义结构体

typedef是类型定义的意思。typedef struct 是为了使用这个结构体方便。

若struct SeqList {}这样来定义结构体的话。在申请SeqList 的变量时,需要这样写,struct SList n;
若用typedef,可以这样写,typedef struct SList{}SL; 。在申请变量时就可以这样写,SL n;
区别就在于使用时,是否可以省去struct这个关键字。

SList.h声明函数

//给int类型起一个别名——SLNDataType
typedef int SLNDataType;
typedef struct SListNode
{
	SLNDataType val;
	struct SListNode* next;
}SLNode;

2.2 单链表打印

SeqList.h声明函数

// 单链表打印
void SLTPrint(SLNode* phead);

SList.c定义函数

//打印结构体
void SLTPrint(SLNode* phead)
{
	SLNode* cur = phead;//指向头节点
	while (cur != NULL)
	{
		printf("%d-> ", cur->val);
		cur = cur->next;
	}
	printf("NULL\n");
}

2.3 销毁单链表

动态开辟的空间用完之后都需要释放,以防后面出现问题。
SList.h声明函数

//单链表销毁
void SLTDestroy(SLNode** pphead);

SList.c定义函数

//单链表销毁
void SLTDestroy(SLNode** pphead)
{
	assert(pphead);
	SLNode* cur = *pphead;
	SLNode* prev = NULL;
	while (cur != NULL)
	{
		prev = cur->next;
		free(cur);
		cur = prev;
	}
	*pphead = NULL;
}

2.4 动态申请一个结点

无论在链表头部、尾部还是任意位置插入一个节点,都需要开辟一个节点,每个插入函数里都要写开辟节点的函数会重复,为了方便,我们单独定义一个函数用来开辟新节点,每次只需调用即可。
SList.c定义函数

SLNode* CreateNode(SLNDataType x)
{
	//让指针newnode指向malloc开辟的新空间
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	if (newnode == NULL)//开辟失败则返回错误信息
	{
		perror("malloc fail");
		exit(-1);
	}
	//对结构体成员解引用,改变其值
	newnode->val = x;
	//让next指向空
	newnode->next = NULL;
	return newnode;
}

2.5 单链表尾插

思路:
新建一个节点,让链表最后一个节点的next指向新节点
在这里插入图片描述

SList.h声明函数

// 单链表尾插
void SLTPushBack(SLNode** pphead, SLNDataType x);

SList.c定义函数
如果这个链表中没有任何节点,只需让头部指针plist直接指向newnode。
需要注意的一点是,plist是一级指针,我们想改变plist,就要用二级指针来接收plist的地址,这样才能改变plist的指向

// 单链表尾插
void SLTPushBack(SLNode** pphead, SLNDataType x)
{
	assert(pphead);

	SLNode* newnode = CreateNode(x);
	//如果开头为空,则直接指向CreateNode()函数开辟的空间,完成尾插
	if (*pphead == NULL)
	{
		*pphead = newnode;
		//改变外部结构体指针Node*,要用Node**
	}
	else
	{
		//找尾
		SLNode* tail = *pphead;
		//如果结构体成员next指向的不是空指针
		while (tail->next != NULL)
		{
			//让tail指向下一个节点
			tail = tail->next;
		}
		//再让tail节点的next指向新开辟的空间,完成尾插
		tail->next = newnode;
	}
}

在这里插入图片描述

study.c调用

//测试尾插和尾删
void TestSLT1()
{
	SLNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);

	SLTPrint(plist);
	SLTDestroy(&plist);
}

int main()
{
	TestSLT1();
	return 0;
}

在这里插入图片描述

2.6 单链表尾删

找到倒数第二个节点,让其next指向NULL,用free()释放那个最后一个节点。
如果只有一个节点,直接释放头节点即可。
在这里插入图片描述

SList.h声明函数

// 单链表尾删
void SLTPopBack(SLNode** pphead);

SList.c定义函数

// 单链表尾删
void SLTPopBack(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	//只有一个节点时
	if ((*pphead)->next == NULL)
	{
		//直接释放
		free(*pphead);
		*pphead = NULL;
	}
	//多个节点
	else
	{
		//tail指向开头
		SLNode* tail = *pphead;
		//再定义一个空指针
		SLNode* prev = NULL;
		//next成员指向的下一节点不为空
		while (tail->next != NULL)
		{
			//让prev指向tail所指向的空间
			prev = tail;
			//tail指向下一个节点
			tail = tail->next;
		}
		//循环结束,tail指向的为空,释放空间
		free(tail);
		//再让prev指向的结构体内的next成员指向NULL,完成尾删
		prev->next = NULL;
	}
}

在这里插入图片描述

study.c调用

//测试尾插和尾删
void TestSLT1()
{
	SLNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);

	SLTPopBack(&plist);
	SLTPrint(plist);
	SLTDestroy(&plist);
	SLTPrint(plist);
}
int main()
{
	TestSLT1();
	return 0;
}

在这里插入图片描述

2.7 单链表头插

让头节点plist指向新开辟的节点,再让新开辟节点的next指向之前的第一个节点。
在这里插入图片描述

SList.h声明函数

//单链表头插
void SLTPushFront(SLNode** pphead, SLNDataType x);

SList.c定义函数

// 单链表头插
void SLTPushFront(SLNode** pphead, SLNDataType x)
{
	assert(pphead);
	//让* newnode指向CreateNode()函数开辟的新空间
	SLNode* newnode = CreateNode(x);
	//让新开辟的节点内的next成员指向链表开头的节点
	newnode->next = *pphead;
	//再重新让之前的头节点指向新开辟的节点,完成头插
	*pphead = newnode;
}

在这里插入图片描述

study.c调用

//测试头插和头删
void TestSLT2()
{
	SLNode* plist = NULL;
	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);

	SLTDestroy(&plist);
}
int main()
{
	TestSLT2();
	return 0;
}

在这里插入图片描述

2.8 单链表头删

让plist指向第二个节点,释放第一个节点。
在这里插入图片描述

SList.h声明函数

// 单链表头删
void SListPopFront(SLNode** pphead);

SList.c定义函数

// 单链表头删
void SListPopFront(SLNode** pphead)
{
	assert(*pphead);
	//tail指向开头
	SLNode* tail = *pphead;
	//让头节点指针指向下一个节点
	*pphead = (*pphead)->next;
	//把第一个节点空间释放,完成头删
	free(tail);
	tail = NULL;
}

study.c调用

//测试头插和头删
void TestSLT2()
{
	SLNode* plist = NULL;
	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);
	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTDestroy(&plist);
}
int main()
{
	TestSLT2();
	return 0;
}

在这里插入图片描述

2.9 单链表查找

想要查找链表里的val里是否存入有一个值,遍历链表,查看每个节点的val值,找到则返回该节点的地址,找不到返回-1,具体的作用我们到后面应用。
在这里插入图片描述

SList.h声明函数

// 单链表查找
SLNode* SListFind(SLNode* pphead, SLNDataType x);

SList.c定义函数

SLNode* SListFind(SLNode* phead, SLNDataType x)
{
	SLNode* cur = phead;
	while (cur)
	{
		if (cur->val == x)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return NULL;
}

2.10 单链表任意插入

单链表的插入不止是头插和尾插,可以在任意位置插入。
比如我们在链表中一个数值前插入节点,就可以利用单链表查找来找到这个数,返回其节点的位置,然后在该位置插入节点。
在这里插入图片描述

如果pos位置刚好在第一个节点,就是头插,直接调用之前的头插函数即可

SList.h声明函数

void SLTInsert(SLNode** pphead, SLNode* pos, SLNDataType x);

SList.c定义函数

void SLTInsert(SLNode** pphead, SLNode* pos, SLNDataType x)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);
	
	//单节点
	if (*pphead == pos)
	{
		SLTPushFront(pphead, x);
	}
	//多节点
	else
	{
		SLNode* tail = *pphead;
		while (tail->next != pos)
		{
			tail = tail->next;
		}
		SLNode* newnode = CreateNode(x);
		tail->next = newnode;
		newnode->next = pos;
	}
}

在这里插入图片描述

study.c调用

void TestSLT3()
{
	SLNode* plist = NULL;
	SLTPushBack(&plist, 10);
	SLTPushBack(&plist, 20);
	SLTPushBack(&plist, 30);
	SLTPushBack(&plist, 40);
	SLTPrint(plist);

	SLNode* pos = SListFind(plist, 30);

	if (pos != NULL)
	{
		SLTInsert(&plist, pos, 3);
		SLTPrint(plist);
	}
	SLTDestroy(&plist);
}
int main()
{
	TestSLT3();
	return 0;
}

在这里插入图片描述

2.11 单链表任意删除

和任意插入差不多,如果pos位置在头部就是头删,直接调用即可。
SList.h声明函数

//单链表任意位置删除
void SLTErase(SLNode** pphead, SLNode* pos);

SList.c定义函数

//单链表任意位置删除
void SLTErase(SLNode** pphead, SLNode* pos)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);

	SLNode* tail = *pphead;
	if (*pphead == pos)
	{
		SLTPopFront(pphead);
	}
	else
	{
		while (tail->next != pos)
		{
			tail = tail->next;
		}
		tail->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

study.c调用

//单链表任意位置插入和删除
void TestSLT3()
{
	SLNode* plist = NULL;
	SLTPushBack(&plist, 10);
	SLTPushBack(&plist, 20);
	SLTPushBack(&plist, 30);
	SLTPushBack(&plist, 40);
	SLTPrint(plist);

	SLNode* pos = SListFind(plist, 30);
	if (pos != NULL)
	{
		SLTErase(&plist, pos);
	}
	SLTPrint(plist);
	SLTDestroy(&plist);
}

int main()
{
	TestSLT3();
	return 0;
}

在这里插入图片描述

3. 代码整理

3.1 SList.h声明函数

#pragma once
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

// 动态申请一个结点
typedef int SLNDataType;
typedef struct SListNode
{
	SLNDataType val;
	struct SListNode* next;
}SLNode;

// 单链表打印
void SLTPrint(SLNode* phead);
//单链表销毁
void SLTDestroy(SLNode** pphead);
// 单链表尾插
void SLTPushBack(SLNode** pphead, SLNDataType x);
//单链表头插
void SLTPushFront(SLNode** pphead, SLNDataType x);
// 单链表尾删
void SLTPopBack(SLNode** pphead);
// 单链表头删
void SLTPopFront(SLNode** pphead);
// 单链表查找
SLNode* SListFind(SLNode* pphead, SLNDataType x);

// 单链表任意位置插入
void SLTInsert(SLNode** pphead, SLNode* pos, SLNDataType x);
//单链表任意位置删除
void SLTErase(SLNode** pphead, SLNode* pos);


void SLTInsertAfter(SLNode* pos, SLNDataType x);
void SLTEraseAfter(SLNode* pos);

3.2 SList.c定义函数

#include "SList.h"

//打印结构体
void SLTPrint(SLNode* phead)
{
	SLNode* cur = phead;//指向头节点
	while (cur != NULL)
	{
		printf("%d-> ", cur->val);
		cur = cur->next;
	}
	printf("NULL\n");
}

//单链表销毁
void SLTDestroy(SLNode** pphead)
{
	assert(pphead);
	SLNode* cur = *pphead;
	SLNode* prev = NULL;
	while (cur != NULL)
	{
		prev = cur->next;
		free(cur);
		cur = prev;
	}
	*pphead = NULL;
}

SLNode* CreateNode(SLNDataType x)
{
	//让指针newnode指向malloc开辟的新空间
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	if (newnode == NULL)//开辟失败则返回错误信息
	{
		perror("malloc fail");
		exit(-1);
	}
	//对结构体成员解引用,改变其值
	newnode->val = x;
	//让next指向空
	newnode->next = NULL;
	return newnode;
}
// 单链表尾插
void SLTPushBack(SLNode** pphead, SLNDataType x)
{
	assert(pphead);

	SLNode* newnode = CreateNode(x);
	//如果开头为空,则直接指向CreateNode()函数开辟的空间,完成尾插
	if (*pphead == NULL)
	{
		*pphead = newnode;
		//改变外部结构体指针Node*,要用Node**
	}
	else
	{
		//找尾
		SLNode* tail = *pphead;
		//如果结构体成员next指向的不是空指针
		while (tail->next != NULL)
		{
			//让tail指向下一个节点
			tail = tail->next;
		}
		//再让tail节点的next指向新开辟的空间,完成尾插
		tail->next = newnode;
	}
}

// 单链表尾删
void SLTPopBack(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	//只有一个节点时
	if ((*pphead)->next == NULL)
	{
		//直接释放
		free(*pphead);
		*pphead = NULL;
	}
	//多个节点
	else
	{
		//tail指向开头
		SLNode* tail = *pphead;
		//再定义一个空指针
		SLNode* prev = NULL;
		//next成员指向的下一节点不为空
		while (tail->next != NULL)
		{
			//让prev指向tail所指向的空间
			prev = tail;
			//tail指向下一个节点
			tail = tail->next;
		}
		//循环结束,tail指向的为空,释放空间
		free(tail);
		//再让prev指向的结构体内的next成员指向NULL,完成尾删
		prev->next = NULL;
	}

}

// 单链表头插
void SLTPushFront(SLNode** pphead, SLNDataType x)
{
	assert(pphead);

	//让* newnode指向CreateNode()函数开辟的新空间
	SLNode* newnode = CreateNode(x);
	//让新开辟的节点内的next成员指向链表开头的节点
	newnode->next = *pphead;
	//再重新让之前的头节点指向新开辟的节点,完成头插
	*pphead = newnode;
}


// 单链表头删
void SLTPopFront(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	//tail指向开头
	SLNode* tail = *pphead;
	//让头节点指针指向下一个节点
	*pphead = (*pphead)->next;
	//把第一个节点空间释放,完成头删
	free(tail);
	tail = NULL;
}

// 单链表查找
SLNode* SListFind(SLNode* phead, SLNDataType x)
{
	SLNode* cur = phead;
	while (cur)
	{
		if (cur->val == x)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return NULL;
}

// 单链表任意位置插入
void SLTInsert(SLNode** pphead, SLNode* pos, SLNDataType x)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);
	//单节点
	if (*pphead == pos)
	{
		SLTPushFront(pphead, x);
	}
	//多节点
	else
	{
		SLNode* tail = *pphead;
		while (tail->next != pos)
		{
			tail = tail->next;
		}
		SLNode* newnode = CreateNode(x);
		tail->next = newnode;
		newnode->next = pos;
	}
}

//单链表任意位置删除
void SLTErase(SLNode** pphead, SLNode* pos)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);

	SLNode* tail = *pphead;
	if (*pphead == pos)
	{
		SLTPopFront(pphead);
	}
	else
	{
		while (tail->next != pos)
		{
			tail = tail->next;
		}
		tail->next = pos->next;
		free(pos);
		pos = NULL;
	}
}


void SLTInsertAfter(SLNode* pos, SLNDataType x)
{
	assert(pos);
	SLNode* newnode = CreateNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}
void SLTEraseAfter(SLNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLNode* tmp = pos->next;
	pos->next = pos->next->next;
	free(tmp);
	tmp = NULL;
}

3.3 study.c调用

#define _CRT_SECURE_NO_WARNINGS 
#include "SList.h"
//每个节点的地址没有关联,是随机的,东一个,西一个

//想要改变int*,传的就要是int**

//测试尾插和尾删
void TestSLT1()
{
	SLNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);

	SLTPopBack(&plist);
	SLTPrint(plist);
	SLTDestroy(&plist);
	SLTPrint(plist);

}
//测试头插和头删
void TestSLT2()
{
	SLNode* plist = NULL;
	SLTPushFront(&plist, 10);
	SLTPushFront(&plist, 20);
	SLTPushFront(&plist, 30);
	SLTPushFront(&plist, 40);
	SLTPrint(plist);

	SLTPopFront(&plist);
	SLTPrint(plist);
	SLTPopFront(&plist);
	SLTPrint(plist);

	SLTDestroy(&plist);
	
}

//单链表任意位置插入和删除
void TestSLT3()
{
	SLNode* plist = NULL;
	SLTPushBack(&plist, 10);
	SLTPushBack(&plist, 20);
	SLTPushBack(&plist, 30);
	SLTPushBack(&plist, 40);
	SLTPrint(plist);

	SLNode* pos = SListFind(plist, 30);

	/*if (pos != NULL)
	{
		SLTInsert(&plist, pos, 3);
		SLTPrint(plist);
	}
	SLTDestroy(&plist);*/


	if (pos != NULL)
	{
		SLTErase(&plist, pos);
	}
	SLTPrint(plist);
	SLTDestroy(&plist);
}
int main()
{
	//TestSLT1();
	//TestSLT2();
	TestSLT3();
	return 0;
}

4. 博主有话说

有关无头单链表的内容就分享到这里,更多有关内容关注博主,有问题可以留言和博主讨论。

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

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

相关文章

nav2 调节纯追踪算法

纯追踪算法 纯追踪基础 The core idea is to find a point on the path in front of the robot and find the linear and angular velocity to help drive towards it. 核心思想是在机器人前方的路径上找到一个点&#xff0c;并找到一个合适的线速度和角速度&#xff0c;以驱…

深入理解JVM虚拟机第二十二篇:详解JVM当中与操作数栈相关的字节码指令

大神链接&#xff1a;作者有幸结识技术大神孙哥为好友&#xff0c;获益匪浅。现在把孙哥视频分享给大家。 孙哥链接&#xff1a;孙哥个人主页 作者简介&#xff1a;一个颜值99分&#xff0c;只比孙哥差一点的程序员 本专栏简介&#xff1a;话不多说&#xff0c;让我们一起干翻J…

【无代码】【VR开发】【Unity】【VRTK】4-导入VRTK Tilia Package

【导入VRTK V4】 VRTK的Tilia Package包含了一整套空间开发方案。导入后你可以在PackageManager中看到它们。 所有的Tilia包都可以在如下页面找到: https://www.vrtk.io/tilia.html Tilia包有一个安装器,可以让你仅仅安装需要的包。包的种类很多,按照适用方向分类。 点击H…

C++ 之多态(一)

什么是虚函数 在类的定义中&#xff0c;前面有 virtual 关键字的成员函数称为虚函数&#xff1b;virtual 关键字只用在类定义里的函数声明中&#xff0c;写函数体时不用。 class Base {virtual int Fun() ; // 虚函数 };int Base::Fun() // virtual 字段不用在函数体时定义 …

react 实现chatGPT的打印机效果 兼容富文本,附git地址

1、方式一 &#xff1a;使用插件 typed.js typed.js 网站地址&#xff0c;点我打开 1.1、核心代码如下&#xff1a; //TypeWriteEffect/index.tsx 组件 import React, { useEffect, useRef } from react; import Typed from typed.js; import { PropsType } from ./index.d;…

t2017递推3骨牌

答案&#xff1a; #include<iostream> using namespace std; long long n,s[10009]; int main() {cin>>n;s[1]1,s[2]2,s[3]4;if(n1){cout<<1;return 0;}if(n2){cout<<2;return 0;}if(n3){cout<<4;return 0;}for(int i4;i<n;i)s[i]s[i-1]s[i…

什么是观察者模式?用 Python 如何实现 Observer(观察者或发布订阅)对象行为型模式?

什么是观察者模式&#xff1f; 观察者模式&#xff08;Observer pattern&#xff09;是一种行为型设计模式&#xff0c;它允许对象之间建立一种一对多的依赖关系&#xff0c;当一个对象的状态发生变化时&#xff0c;其相关依赖对象都会得到通知并自动更新。 在观察者模式中&am…

【服务发现与配置】Consul特性及搭建

文章目录 一、前言二、概念2.1、什么是Consul&#xff1f;2.2、Consul具有哪些特点?2.3、Consul 架构图2.4、Consul的使用场景 三、安装3.1. 下载3.2. 解压3.3. 拷贝到usr目录下3.4. 查看 安装是否成功3.5. 启动 四、Consul 开机自启动4.1. 路径/usr/lib/systemd/system/&…

【Qt之QMetaType】使用

介绍 QMetaType类管理元对象系统中的命名类型。 该类用作QVariant和排队的信号与槽连接中类型的编组辅助器。它将类型名称与类型关联起来&#xff0c;以便可以在运行时动态创建和销毁它。使用Q_DECLARE_METATYPE()声明新类型&#xff0c;以使它们可供QVariant和其他基于模板的…

三菱FX3U系列—原点回归指令

目录 一、简介 二、指令形式 1、原点指令[ZRN/DZRN] 2、带搜索的原点回归指令[DSZR] 三、回归指令运行过程 1、ZRN原点回归运行过程 2、带搜索的原点回归运行过程 四、特殊辅助继电器 五、特殊输出模块 六、总结 一、简介 用于将电机或伺服驱动器控制的轴回到预定的原…

浙江大学漏洞报送证书

获取来源&#xff1a;edusrc&#xff08;教育漏洞报告平台&#xff09; url&#xff1a;主页 | 教育漏洞报告平台 兑换价格&#xff1a;20金币 获取条件&#xff1a;提交浙江大学任意中危或以上级别漏洞

socks5代理和https代理有什么不同?各自有哪些优点?

socks5代理和https代理是两种不同的代理服务&#xff0c;它们在实现方式、安全性和协议特点等方面存在差异。下面我们来详细了解一下这两种代理的优点。 一、socks5代理的优点 1. 速度快 socks5代理采用了TCP协议&#xff0c;能够有效地减少网络延迟和数据传输速度慢的问题&…

Ubuntu22.04下挂载共享文件夹

1.在自己Windows任意地方建一个文件夹 2.打开虚拟机做如下配置 3.开启虚拟机&#xff0c;打开终端 4.输入&#xff1a;vmware-hgfsclient 看到物理机共享文件夹 5.输入&#xff1a;sudo mkdir /mnt/hgfs 创建虚拟机中的共享文件夹 6.输入&#xff1a;sudo vmhgfs-fuse .h…

离散数学第一章知识点复习

命题&#xff1a;陈述句 真值已经确定 原子命题&#xff08;简单命题&#xff09;&#xff1a;不能被分解为更简单的命题 命题化的时候的解题步骤&#xff1a; 1. 先给出原子命题 2. 符号化 注意蕴含式&#xff1a;记作 p -> q &#xff0c;p是前件&#xff0c;q 是后…

软件版本控制系统VCS工具——cvs vss svn git

版本控制 版本控制系统&#xff08;Version Control System&#xff0c;VCS&#xff09;是用于跟踪和管理源代码和文档的工具。可追踪和管理修改历史&#xff0c;包括修改的内容、时间、作者等信息。有助于团队协作、追踪变更、恢复历史版本等。VCS的主要目的是帮助团队协作开…

如何写一篇吊炸天的竞品分析

这段时间&#xff0c;除了撩妹之外&#xff0c;最多的就是竞品分析了。最近很多临近毕业的同学也在四处应聘产品岗&#xff0c;而一份不错的竞品分析一定能为你的求职加分不少。于是&#xff0c;有着菩萨心肠天使面孔魔鬼身材的我&#xff0c;就来教大家怎么做一份完整的竞品分…

什么是代理IP池?真实测评IP代理商的IP池是否真实?

代理池充当多个代理服务器的存储库&#xff0c;提供在线安全和匿名层。代理池允许用户抓取数据、访问受限制的内容以及执行其他在线任务&#xff0c;而无需担心被检测或阻止的风险。代理池为各种在线活动&#xff08;例如网页抓取、安全浏览等&#xff09;提高后勤保障。 读完…

【Bug】Python利用matplotlib绘图无法显示中文解决办法

一&#xff0c;问题描述 当利用matplotlib进行图形绘制时&#xff0c;图表标题&#xff0c;坐标轴&#xff0c;标签中文无法显示&#xff0c;显示为方框&#xff0c;并报错 运行窗口报错&#xff1a; 这是中文字体格式未导入的缘故。 二&#xff0c;解决方案 在代码import部…

将 Figma 轻松转换为 Sketch 的免费方法

最近浏览网站的时候&#xff0c;发现很多人不知道Figma是怎么转Sketch的。众所周知&#xff0c;Figma支持Sketch文件的导入&#xff0c;但不支持Sketch的导出&#xff0c;那么Figma是如何转Sketch的呢&#xff1f;不用担心&#xff0c;建议使用神器即时设计。它是一个可以实现在…

systemctl enable docker.service报错“Failed to execute operation: Bad message“

将docker加入到开机自启&#xff0c;报错&#xff1a; 解决&#xff1a; 重新粘贴复制&#xff1a; [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service Wantsnetwork-online.target…