链表基础知识(二、双向链表头插、尾插、头删、尾删、查找、删除、插入)

news2024/11/25 8:14:24

目录

一、双向链表的概念

二、 双向链表的优缺点分析​与对比

 2.1双向链表特点:

2.2双链表的优劣:

2.3循环链表的优劣

2.4 顺序表和双向链表的优缺点分析​

三、带头双向循环链表增删改查实现

3.1SList.c

3.2创建一个新节点、头节点

3.3头插

3.4尾插

3.5头删

3.6尾删

3.7查找

3.8删除

3.9插入

3.10查找

3.11打印链表

3.12销毁链表

四、简化链表,用插入和删除代替其他插入删除

五、SList.h

六、Test.c


书接上文:

链表基础知识(一、单链表、头插、尾插、头删、尾删、查找、删除、插入)-CSDN博客

一、双向链表的概念

双向链表,即一个节点中有两个指针域,一个存放当前节点前一个节点的地址,另一个存放当前节点后一个节点的地址。

(STL中list就是这个结构)

双链表的节点:

二、 双向链表的优缺点分析​与对比

 2.1双向链表特点:

       1.每次在插入或删除某个节点时, 需要处理四个节点的引用, 而不是两个. 实现起来要困难一些
  2.相对于单向链表, 必然占用内存空间更大一些.
  3.既可以从头遍历到尾, 又可以从尾遍历到头

2.2双链表的优劣:

2.3循环链表的优劣

循环表的好处主要包括以下几点:

  • 灵活性:循环链表可以从任何一个节点开始遍历,而且任何节点都可以作为头节点。这种灵活性使得循环链表在处理某些问题时比其他类型的链表更有优势。

  • 简化操作:在循环链表中,插入和删除操作相对简便,不需要对头尾节点

  • 行特殊处理。这种简便性可以提高算法的效率,降低编程的复杂性。

  • 适用于循环问题:循环链表可以实现循环访问,因此特别适用于解决涉及到循环问题的场景。

  • 便于实现队列数据结构:使用循环链表来实现队列数据结构可以简化操作,只需要维护一个尾节点指针即可,因为尾节点的后向节点就是队头节点。

  • 方便操作系统管理和应用程序运行:循环链表在操作系统和应用程序中也有广泛的应用。例如,操作系统可以利用循环链表来管理多个应用程序,通过循环遍历来给每个应用程序分配执行时间。

  • 可用于实现高级数据结构:循环双向链表可以用于实现高级数据结构,例如斐波那契堆(Fibonacci Heap),从而扩展了其在复杂算法和数据结构中的应用范围。

循环链表的缺点主要包括:

  • 内存占用更多:相比单链表,循环链表需要更多的内存空间来存储链接信息。这是因为循环链表中的每个节点都需要指向下一个节点,形成一个闭环,从而增加了内存开销。

  • 代码复杂度提高:循环链表的代码实现相比单链表要复杂一些。在插入、删除节点或遍历链表时,需要特别注意处理边界条件和循环结构,这可能会增加开发和调试的难度。

  • 潜在的死循环风险:如果循环链表中的链接关系出现错误,可能会导致死循环的情况发生。例如,在插入或删除节点时,如果没有正确更新链接关系,就可能导致链表无法正确遍历或陷入无限循环中。

2.4 顺序表和双向链表的优缺点分析​

三、带头双向循环链表增删改查实现

结构复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面我们代码实现了就知道了。

3.1SList.c

#pragma once
#define  _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>


typedef int LTDataType;
//带哨兵位的头节点,第一个节点不存储有效数据,不能存储链表的长度
//typedef char LTDataType;
//typedef double LTDataType;无法存储链表长度


//Slist  双向链表
//DList  单链表
typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;
	LTDataType data;
}ListNode;

ListNode* ListInit();
void ListDestory(ListNode* phead);
void ListPrint(ListNode* phead);

void ListPushBack(ListNode* phead, LTDataType x);
void ListPushFront(ListNode* phead, LTDataType x);
void ListPopFront(ListNode* phead);
void ListPopBack(ListNode* phead);

ListNode* ListFind(ListNode* phead, LTDataType x);
// pos位置之前插入x
void ListInsert(ListNode* pos, LTDataType x);
// 删除pos位置的值
void ListErase(ListNode* pos);

//bool ListEmpty(ListNode* phead);
//int ListSize(ListNode* phead);//链表的长度

3.2创建一个新节点、头节点

ListNode* BuyListNode(LTDataType x)
//创建一个新节点
{
	ListNode* newnode = malloc(sizeof(ListNode));
	//malloc分配大小,是一个ListNode结构体的大小
	newnode->data = x;//将新节点的data字段设置为参数x的值
	newnode->next = NULL;//给新节点的next存储的地址置空
	newnode->prev = NULL;//给新节点的prev存储的地址置空

	return newnode;
}
ListNode* ListInit()
//创建头节点
{
	ListNode* phead = BuyListNode(0);//phead指向了这个新创建的节点
	phead->next = phead; // 将phead的 next 指向其自身
	phead->prev = phead; // 将phead的 prev 指向其自身

	return phead;//返回phead,即头节点
}

3.3头插

在头节点后插入

void ListPushFront(ListNode* phead, LTDataType x)
{
	assert(phead);//此节点不为空

	//顺序不能换
	ListNode* newnode = BuyListNode(x);
	newnode->next = phead->next;//存储phead的next,即下一个节点
	phead->next->prev = newnode;//下一个节点的prev指向newnode

	phead->next = newnode;//下一个节点的next 指向 newnode
	newnode->prev = phead;//newnode的prev 指向 phead
}

3.4尾插

在头节点前插入

void ListPushBack(ListNode* phead, LTDataType x)
//x = 0,尾插
{
	assert(phead);//phead不为空
	ListNode* tail = phead->prev;//tail存储phead的prev中的地址,即最后一个节点
	ListNode* newnode = BuyListNode(x);//创建一个新节点
	
	tail->next = newnode;//上一个节点的next指向新节点
	newnode->prev = tail;//新节点的prev指向phead
	newnode->next = phead;//新节点的next指向phead
	phead->prev = newnode;//上一个节点的prev指向新节点
}

3.5头删

在头结点后删除

void ListPopFront(ListNode* phead)
{
	assert(phead);//phead不为空
	assert(phead->next != phead);

	ListNode* first = phead->next;//先first存储phead的next中的地址,即phead的下一个节点
	ListNode* second = first->next;//再second存储下一个的节点的next中的地址,即下下个节点
	phead->next = second;//phead的next指向下下一个节点
	second->prev = phead;//下下一个节点的prev指向phead

	free(first);//下一个节点的空间被释放
	first = NULL;//first置空
}

3.6尾删

在头节点前删除

void ListPopBack(ListNode* phead)
{
	assert(phead);//此节点不为空
	assert(phead->next != phead);

	ListNode* tail = phead->prev;//先tail存储phead的prev中的地址,即上一个节点
	ListNode* prev = tail->prev;//prev存储上一个节点的prev中的地址,即上上一个节点

	prev->next = phead;//上上个节点的next指向phead
	phead->prev = prev;//phead的prev指向上上个节点

	free(tail);//释放tail存储的空间,即上个节点的空间
	tail = NULL;//tail置空
	
}

3.7查找

ListNode* ListFind(ListNode* phead, LTDataType x)
{
	assert(phead);//此节点不为空
	ListNode* cur = phead->next;//cur存储phead的next中的地址,即下一个节点
	while (cur != phead)//不是头节点
	{
		if (cur->data == x)//如果是要查找的地址
		{
			return cur;//找到了返回这个地址
		}

		cur = cur->next;//指向下一个节点
	}

	return NULL;//没有找到,返回空
}

3.8删除

// 删除pos位置的值
void ListErase(ListNode* pos)
{
	assert(pos);//此节点不为空

	ListNode* prev = pos->prev;//prev存储pos的prev中的地址,即上一个节点
	ListNode* next = pos->next;//next存储pos的next中的地址,即下一个节点
	prev->next = next;//上一个节点的next指向pos的next,即下一个节点
	next->prev = prev;//下一个节点的prev指向pos的prev,即上一个节点
	free(pos);//释放pos所在的空间
}

3.9插入

// pos位置之前插入x
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);//此节点不为空
	ListNode* prev = pos->prev;//prev存储pos的prev中的地址,即pos上一个节点
	ListNode* newnode = BuyListNode(x);//创建一个新节点

	// prev newnode pos
	prev->next = newnode;//上一个节点的next指向newnode
	newnode->prev = prev;//新节点的prev指向上一个节点
	newnode->next = pos;//新节点的next指向pos
	pos->prev = newnode;//pos的prev指向newnode
}

3.10查找

ListNode* ListFind(ListNode* phead, LTDataType x)
{
	assert(phead);//此节点不为空
	ListNode* cur = phead->next;//cur存储phead的next中的地址,即下一个节点
	while (cur != phead)//不是头节点
	{
		if (cur->data == x)//如果是要查找的地址
		{
			return cur;//找到了返回这个地址
		}

		cur = cur->next;//指向下一个节点
	}

	return NULL;//没有找到,返回空
}

3.11打印链表

void ListPrint(ListNode* phead)
{
	assert(phead);//此节点不为空

	ListNode* cur = phead->next;//cur存储phead的next中的地址,即下一个节点
	while (cur != phead)//cur不是指向的自己(头节点)
	{								
		printf("%d ", cur->data);
		//打印cur存储的数据,即下一个地址的数据(因为有头节点)
		cur = cur->next;//指向下一个节点
	}
	printf("\n");
}

3.12销毁链表

void ListDestory(ListNode* phead)
{
	assert(phead);//phead不为空
	ListNode* cur = phead->next;//cur存储phead的next中的地址,即下一个节点
	while (cur != phead)//cur指向的不是自己
	{
		ListNode* next = cur->next;//next指向下一个节点
		free(cur);//释放cur所在的空间
		cur = next;//cur指向下一个节点
	}

	free(phead);//释放头节点所在的空间
	phead = NULL;//头节点置空

}

四、简化链表,用插入和删除代替其他插入删除

void ListPushBack(ListNode* phead, LTDataType x)
{
	assert(phead);//phead不为空
	ListInsert(phead, x);//可以用插入来表示尾插
}

void ListPushFront(ListNode* phead, LTDataType x)
{
	assert(phead);//此节点不为空
	ListInsert(phead->next, x);//可以用插入来表示头插
}

void ListPopFront(ListNode* phead)
{
	assert(phead);//phead不为空
	ListErase(phead->next);//可以用删除表示头删
}

void ListPopBack(ListNode* phead)
{
	assert(phead);//此节点不为空
	ListErase(phead->prev);//可以用删除表示尾删
}

// pos位置之前插入x
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);//此节点不为空
	ListNode* prev = pos->prev;//prev存储pos的prev中的地址,即pos上一个节点
	ListNode* newnode = BuyListNode(x);//创建一个新节点

	// prev newnode pos
	prev->next = newnode;//上一个节点的next指向newnode
	newnode->prev = prev;//新节点的prev指向上一个节点
	newnode->next = pos;//新节点的next指向pos
	pos->prev = newnode;//pos的prev指向newnode
}

// 删除pos位置的值
void ListErase(ListNode* pos)
{
	assert(pos);//此节点不为空

	ListNode* prev = pos->prev;//prev存储pos的prev中的地址,即上一个节点
	ListNode* next = pos->next;//next存储pos的next中的地址,即下一个节点
	prev->next = next;//上一个节点的next指向pos的next,即下一个节点
	next->prev = prev;//下一个节点的prev指向pos的prev,即上一个节点
	free(pos);//释放pos所在的空间
}

五、SList.h

#include"List.h"

ListNode* BuyListNode(LTDataType x)
//创建一个新节点
{
	ListNode* newnode = malloc(sizeof(ListNode));
	//malloc分配大小,是一个ListNode结构体的大小
	newnode->data = x;//将新节点的data字段设置为参数x的值
	newnode->next = NULL;//给新节点的next存储的地址置空
	newnode->prev = NULL;//给新节点的prev存储的地址置空

	return newnode;
}

//void ListInit(ListNode* phead)
初始化了链表的新节点
//{
//	phead = BuyListNode(0);//phead指向了这个新创建的节点
//	phead->next = phead;//将phead的 next 指向其自身
//	phead->prev = phead;//将phead的 prev 指向其自身
//}

ListNode* ListInit()
//创建头节点
{
	ListNode* phead = BuyListNode(0);//phead指向了这个新创建的节点
	phead->next = phead; // 将phead的 next 指向其自身
	phead->prev = phead; // 将phead的 prev 指向其自身

	return phead;//返回phead,即头节点
}


void ListDestory(ListNode* phead)
{
	assert(phead);//phead不为空
	ListNode* cur = phead->next;//cur存储phead的next中的地址,即下一个节点
	while (cur != phead)//cur指向的不是自己
	{
		ListNode* next = cur->next;//next指向下一个节点
		free(cur);//释放cur所在的空间
		cur = next;//cur指向下一个节点
	}

	free(phead);//释放头节点所在的空间
	phead = NULL;//头节点置空

}

void ListPrint(ListNode* phead)
{
	assert(phead);//此节点不为空

	ListNode* cur = phead->next;//cur存储phead的next中的地址,即下一个节点
	while (cur != phead)//cur不是指向的自己(头节点)
	{								
		printf("%d ", cur->data);
		//打印cur存储的数据,即下一个地址的数据(因为有头节点)
		cur = cur->next;//指向下一个节点
	}
	printf("\n");
}


void ListPushBack(ListNode* phead, LTDataType x)
//x = 0,尾插
{
	//assert(phead);//phead不为空
	//ListNode* tail = phead->prev;//tail存储phead的prev中的地址,即最后一个节点
	//ListNode* newnode = BuyListNode(x);//创建一个新节点
	//
	//tail->next = newnode;//上一个节点的next指向新节点
	//newnode->prev = tail;//新节点的prev指向phead
	//newnode->next = phead;//新节点的next指向phead
	//phead->prev = newnode;//上一个节点的prev指向新节点
	ListInsert(phead, x);//可以用插入来表示尾插
}



//void ListPushFront(ListNode* phead, LTDataType x)
x = 0,头插
//{
//	assert(phead);//此节点不为空
//
//	ListNode* first = phead->next;//first存储phead的next中的地址,即下一个节点
//	ListNode* newnode = BuyListNode(x);//在x处创建一个新节点
//
//	// phead newnode first
//	phead->next = newnode;//下一个节点的next指向新节点
//	newnode->prev = phead;//新节点的prev指向此节点
//	newnode->next = first;//新节点的next指向此节点
//	first->prev = newnode;//下一个节点的prev指向新节点
//}

void ListPushFront(ListNode* phead, LTDataType x)
{
	assert(phead);//此节点不为空

	//顺序不能换
	ListNode* newnode = BuyListNode(x);
	newnode->next = phead->next;//存储phead的next,即下一个节点
	phead->next->prev = newnode;//下一个节点的prev指向newnode

	phead->next = newnode;//下一个节点的next 指向 newnode
	newnode->prev = phead;//newnode的prev 指向 phead
	//ListInsert(phead->next, x);//可以用插入来表示头插
}

void ListPopFront(ListNode* phead)
{
	assert(phead);//phead不为空
	assert(phead->next != phead);

	ListNode* first = phead->next;//先first存储phead的next中的地址,即phead的下一个节点
	ListNode* second = first->next;//再second存储下一个的节点的next中的地址,即下下个节点
	phead->next = second;//phead的next指向下下一个节点
	second->prev = phead;//下下一个节点的prev指向phead

	free(first);//下一个节点的空间被释放
	first = NULL;//first置空

	//ListErase(phead->next);//可以用删除表示头删
}

void ListPopBack(ListNode* phead)
{
	assert(phead);//此节点不为空
	/*assert(phead->next != phead);

	ListNode* tail = phead->prev;//先tail存储phead的prev中的地址,即上一个节点
	ListNode* prev = tail->prev;//prev存储上一个节点的prev中的地址,即上上一个节点

	prev->next = phead;//上上个节点的next指向phead
	phead->prev = prev;//phead的prev指向上上个节点

	free(tail);//释放tail存储的空间,即上个节点的空间
	tail = NULL;//tail置空
	*/

	ListErase(phead->prev);//可以用删除表示尾删
}

ListNode* ListFind(ListNode* phead, LTDataType x)
{
	assert(phead);//此节点不为空
	ListNode* cur = phead->next;//cur存储phead的next中的地址,即下一个节点
	while (cur != phead)//不是头节点
	{
		if (cur->data == x)//如果是要查找的地址
		{
			return cur;//找到了返回这个地址
		}

		cur = cur->next;//指向下一个节点
	}

	return NULL;//没有找到,返回空
}

// pos位置之前插入x
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);//此节点不为空
	ListNode* prev = pos->prev;//prev存储pos的prev中的地址,即pos上一个节点
	ListNode* newnode = BuyListNode(x);//创建一个新节点

	// prev newnode pos
	prev->next = newnode;//上一个节点的next指向newnode
	newnode->prev = prev;//新节点的prev指向上一个节点
	newnode->next = pos;//新节点的next指向pos
	pos->prev = newnode;//pos的prev指向newnode
}

// 删除pos位置的值
void ListErase(ListNode* pos)
{
	assert(pos);//此节点不为空

	ListNode* prev = pos->prev;//prev存储pos的prev中的地址,即上一个节点
	ListNode* next = pos->next;//next存储pos的next中的地址,即下一个节点
	prev->next = next;//上一个节点的next指向pos的next,即下一个节点
	next->prev = prev;//下一个节点的prev指向pos的prev,即上一个节点
	free(pos);//释放pos所在的空间
}

六、Test.c

#include"List.h"

void TestList1()
{
	ListNode* plist = ListInit();//plist为头节点
	ListPushBack(plist, 1);
	ListPushBack(plist, 2);
	ListPushBack(plist, 3);
	ListPushBack(plist, 4);
	ListPrint(plist);

	ListPushFront(plist, 0);
	ListPushBack(plist, -1);
	ListPrint(plist);

	/*ListPopFront(plist);
	ListPopFront(plist);
	ListPopFront(plist);
	ListPrint(plist);

	ListPopBack(plist);
	ListPrint(plist);

	ListDestory(plist);*/

}

int main()
{
	TestList1();

	return 0;
}

今天就先到这了!!!

看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注!

你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦。

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

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

相关文章

互联网加竞赛 python+opencv+深度学习实现二维码识别

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; pythonopencv深度学习实现二维码识别 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;3分 该项目较为新颖&…

libxls - 编译

文章目录 libxls - 编译概述笔记静态库工程测试控制台exe工程测试备注备注END libxls - 编译 概述 想处理.xls格式的excel文件. 查了一下libxls库可以干这个事. 库地址 https://github.com/libxls/libxls.git 但是这个库的makefile写的有问题, 在mingw和WSL下都编译不了. 好在…

C# WPF上位机开发(进度条操作)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 软件上面如果一个操作比较缓慢&#xff0c;或者说需要很长的时间&#xff0c;那么这个时候最好添加一个进度条&#xff0c;提示一下当前任务的进展…

Kubernetes - 超简单手动安装 Dashboard WebUI

相关链接 ​​​​​​版本对照&#xff1a;Releases kubernetes/dashboard GitHubKubernetes - 一键卸载 Kubernetes-Dashboard-CSDN博客Kubernetes - Dashboard Token 访问登录永不过期配置-CSDN博客 版本推荐 Kubernetes Dashboard&#xff1a;2.0.3Kubernetes&#xff…

基于Springboot的旅游网站设计与实现(论文+调试+源码)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

DSP芯片行业分析:预计2029年将达到57亿美元

DSP芯片用在工业机器人领域&#xff0c;相当于起着关节的作用&#xff0c;有了DSP的控制&#xff0c;机器人反应更迅速&#xff0c;行动更精准。工业机器人在工作中需要处理大量的数据&#xff0c;随着工业机器人的应用日益广泛和普及&#xff0c;DSP芯片在这方面的应用越来越多…

为什么在Android中需要Context?

介绍 在Android开发中&#xff0c;Context是一个非常重要的概念&#xff0c;但是很多开发者可能并不清楚它的真正含义以及为什么需要使用它。本文将详细介绍Context的概念&#xff0c;并解释为什么在Android应用中需要使用它。 Context的来源 Context的概念来源于Android框架…

java21特性学习

jdk21下载地址 JDK21文件 JDK21是javaSE平台最新的长期支持版本。 Java SE Java Archive | Oracle JDK21版本说明 JDK 21 Release Notes, Important Changes, and Information JavaSE 版本字符串格式 Version-String Format JavaSE平台采用了基于时间的发布模型,JDK每六个…

抖店怎么快速起店?不掺杂汤汤水水,全是干货!

我是电商珠珠 我做抖店也已经有三年的时间了&#xff0c;团队也从原来的几人扩大到了70。对于抖店的玩法已经完全摸透熟通&#xff0c;在做店的同时也会带着学生一起做店&#xff0c;他们经常问的问题就是抖店怎么快速起店。 今天&#xff0c;我就来给大家做个分享。根据我的…

适用于 Windows 和 Mac 的 10 款最佳照片恢复软件(免费和付费)

丢失照片很容易。这里点击错误&#xff0c;那里贴错标签的 SD 卡&#xff0c;然后噗的一声&#xff0c;一切都消失了。值得庆幸的是&#xff0c;在技术领域&#xff0c;你可以纠正一些错误。其中包括删除数据或格式化错误的存储设备。 那么&#xff0c;让我们看看可用于从 SD …

提升广东省水泥行业效率的MES解决方案

广东省水泥行业作为我国重要的基础建设材料生产领域之一&#xff0c;提高其生产效率和降低能源消耗具有重要意义。而随着技术的发展&#xff0c;我国的MES系统技术发展&#xff0c;通过引入MES系统成为了实现降本增效目标的必要且有效的手段。MES是一种基于计算机技术的管理工具…

人工智能超分辨率重建:揭秘图像的高清奇迹

导言 人工智能超分辨率重建技术&#xff0c;作为图像处理领域的一项重要创新&#xff0c;旨在通过智能算法提升图像的分辨率&#xff0c;带来更为清晰和细致的视觉体验。本文将深入研究人工智能在超分辨率重建方面的原理、应用以及技术挑战。 1. 超分辨率重建的基本原理 …

Java原来可以这么玩!CV视频合成处理,视频前后拼接,画面合并

前言 本章内容教会你如何用java代码实现 两个视频的画面合并 或者前后拼接。原理是使用了javacv开源jar包&#xff0c;代码经过反复修改&#xff0c;已经实现我能想到的最优最快的实现&#xff0c;如果你有更好更快的实现&#xff0c;欢迎评论区留言&#xff01;&#xff01;&…

YXLON高压发生器维修XRG160/160/GA

依科视朗YXLON高压发生器维修型号包括XRG100/110/120/130/160/225/320/450等。 维修包括&#xff1a;仪器高压发生器维修 X射线机高压发生器维修 CT高压发生器维修 安检设备高压发生器维修等。 高压发生器原理&#xff1a; 简单的说就是直流电震荡后升压,比如说1个小功率,利用…

MetaSploit工具的使用

在命令行输入&#xff1a;msfconsole 启动msf msfconsole 另外的方式 msfdb init msfdb run 查看数据库连接状态 db_status 扫描端口并存储 db_nmap 查看扫描到的数据信息 services MSF常用的模式和命令 搜索模块 search 模块名字 使用模块 use 编号 查看模块使用 sho…

目标检测应用场景—数据集【NO.19】车辆目标检测数据集

写在前面&#xff1a;数据集对应应用场景&#xff0c;不同的应用场景有不同的检测难点以及对应改进方法&#xff0c;本系列整理汇总领域内的数据集&#xff0c;方便大家下载数据集&#xff0c;若无法下载可关注后私信领取。关注免费领取整理好的数据集资料&#xff01;今天分享…

✺ch5——纹理贴图

目录 加载纹理图像文件纹理坐标在着色器中使用纹理&#xff1a;采样器变量和纹理单元纹理贴图&#xff1a;示例程序多级渐远纹理贴图各向异性过滤环绕和平铺透视变形材质——更多OpenGL细节补充说明 纹理贴图是在栅格化的模型表面上覆盖图像的技术。 它是为渲染场景添加真实感的…

Python三级 每周练习题31

如果你感觉有收获&#xff0c;欢迎给我微信扫打赏码 ———— 以激励我输出更多优质内容 练习一: 作业1:编写程序&#xff0c;在下面的字典中找出身高137的同学并输出姓名&#xff0c;如果没找到&#xff0c; 输出没有 a{‘小赵’:136,‘小钱’:141,‘小孙’:146,‘小李’:13…

操作系统基础知识

本文用于记录学习W3schools的操作系统教程&#xff0c;该教程的部分内容比较难懂&#xff0c;所以也参考了其他文章。 操作系统基础知识 一、操作系统概括二、操作系统的8个组件1 流程管理2 I/O设备管理3 文件管理4 网络管理5 内存管理6 磁盘管理(辅助存储管理)7 安全管理8 命令…

Elasticsearch——快速入门

从零基础的内容开始介绍Elasticsearch&#xff0c;主要包含以下内容&#xff1a; Elasticsearch的定义、优点&#xff0c;以及典型的业务场景。Elasticsearch中重要的概念。Elasticsearch典型的接入方式。安装Elasticsearch。使用Kibana调试Elasticsearch。Elasticsearch节点的…