带头循环双向链表详解

news2025/1/16 0:00:50

目录

一、什么是带头循环双向链表?

1.特点:

2.优点:

二、实现接口

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摧毁链表

 三、全部代码

1.接口头文件

2.接口实现

3.测试文件


一、什么是带头循环双向链表?

1.特点:

1.带头:有哨兵位节点,它不用存储数据。对链表进行插入删除操作时也不会影响改节点。

2.双向:组成链表的结构体中的结构体成员有数据,上一个节点的地址和下一个节点的地址

3.循环:链表的头结点存储了尾结点的地址,链表的尾结点存储了头节点的地址。

2.优点:

相比单向链表,双向循环链表的优点在于它的尾插找尾巴非常的快    因为它的头节点同时存储了上一个节点的地址,头的上一个即尾。相比无头链表,带头链表的好处在于当没有节点的时候,可以直接通过访问结构体成员的方式来增加相应的指针,而无头的话需要直接对地址进行修改,传变量的时候还需要传递二级指针   不仅不好理解,还易在实现的时候出错。

二、实现接口

1.前置准备

1.1需要的三个文件

先创建两个.c文件,再创建一个头文件,分别命名为test.c,list.c,list.h

test.c用来测试写好的接口                                   list.c存放实现接口的代码

list.h则存放对应函数,头文件,结构体的声明,这样在想使用链表的接口时,直接引用list.h即可,不需要引用别的头文件。 

创建好的环境如图

1.2结构体的创建和头文件的引用

这些内容放在list.h的文件中,到时引用就可以一条龙带走,不需要再引用别的内容

#pragma once//防止头文件二次引用
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDateType;
//这样创建结构体数据类型,不仅是为了和int做区分
//也是为了到时更好的替换,想换直接把int改了就行
typedef struct listnode
{
	struct listnode* prev;//存放上一个节点的地址
	struct listnode* next;//存放下一个节点的地址
	LTDateType data;//该节点存放的数据
}listnode;

2.接口实现

2.1函数创建新节点

创建节点,虽然简单,但我们在很多操作中都会用到,因此把它单独分装成一个接口

listnode* buy_listnode(LTDateType x)
{
	listnode*newnode=(listnode*)malloc(sizeof(listnode));
	if (newnode == NULL)
	{
		perror("buy_listnode");//错误提示
		exit(-1);//节点都没创建出来,直接退出程序
	}
	newnode->data = x;//将新节点的数据初始化成我们需要的
	newnode->next = NULL;//不清楚插入的方式,先初始化成空
	newnode->prev = NULL;
}

2.2打印链表内容

非常经典的操作,遍历一遍链表即可,唯一需要注意的便是,哨兵节点不是链表中真正的成员,它只能算是实现链表的辅助,因此跳过哨兵节点进行打印

void print_list(listnode* phead)
{
	assert(phead);//哨兵节点地址不可能为空
	listnode* head = phead->next;
	//哨兵位节点不存储有效数据,因此phead->next才是头节点
	printf("head<=>");//纯属美观
	while (head != phead)//当head和phead相等意味着已经遍历完一遍链表
	{
		printf("%d<=>", head->data);
		head = head->next;
	}
	printf("\n");
}

 2.3尾插新节点

void list_pushback(listnode*phead,LTDateType x)
//尾插一个新节点,此节点存储x
{
	listnode* newnode = buy_listnode(x);
	//创建一个我们需要的新节点
	listnode* tail = phead->prev;
	//先找尾,尾很显然是哨兵位节点的上一个节点
	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}

后面的4行代码是核心,单独在文章中解释,创建了一个新节点,要把它放到链表的末端,尾节点我们已经找到了,接下来就是链接即可

首先明确,新的尾巴是创建出来的新节点,但还没进行链接之前,尾巴还是之前的尾巴

原始链表

第一步: 

第二步: 

 

第三步:

 第四步:

测试代码:

#include"list.h"
void test1()
{
	listnode* plist=NULL;
	plist=init_listnode(plist);
	list_pushback(plist,1);
	list_pushback(plist,2);
	list_pushback(plist,3);
	list_pushback(plist,4);
	print_list(plist);
}
int main()
{
	test1();
}

 测试效果:

2.4头插新节点

这里我就不再画图了,自己画一遍比看别人画一万遍都来的快 

void list_pushfront(listnode* phead, LTDateType x)
{
	listnode* head = phead->next;//找到头节点
	listnode* newnode = buy_listnode(x);//创建新节点
	head->prev = newnode;
	newnode->next = head;
	phead->next = newnode;
	newnode->prev = phead;
}

测试代码:

void test2()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	print_list(plist);
	list_pushfront(plist, 10086);
	print_list(plist);
}
int main()
{
	test2();
}

测试效果: 

 2.5头删节点

需要注意的一点便是,我们删的节点不是哨兵节点,哨兵节点是不存放有效数据的,我们删除的是头节点

void list_popfront(listnode*phead)
{
	assert(phead);
	if (phead->next == phead)
	{
		printf("链表为空,操作失败\n");//为空就别删了
		return;
	}
	listnode* head = phead->next;//找到头节点
	phead->next = head->next;
	head->next->prev = phead;
	free(head);//链接完成,彻底删除
}

测试代码:

void test3()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	print_list(plist);
	list_pushfront(plist, 10086);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
}
int main()
{
	test3();
}

测试效果:

 

2.6尾删节点

没什么好说的,和之前的一样关键点在链接上,自己画了图什么都知道

void list_popback(listnode*phead)
{
	assert(phead);
	if (phead->next == phead)
	{
		printf("链表为空,操作失败\n");//为空就别删了
		return;
	}
	listnode* tail = phead->prev;//找到尾节点
	phead->prev = tail->prev;
	tail->prev->next = phead;
	free(tail);
}

测试代码:

void test4()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 10086);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
}
int main()
{
	test4();
}

测试效果: 

 2.7查找节点

遍历一遍,找不到就返回NULL即可

listnode* list_find(listnode* phead, LTDateType x)
//哨兵节点和目标
{
	assert(phead);
	listnode* head = phead->next;//找到头节点
	while (head!=phead)//相等意味着已经遍历完了
	{
		if (head->data == x)
		//找到目标,直接返回
		{
			return head;
		}
		head = head->next;
	}
	return NULL;//遍历完还找不到,返回空指针
}

2.8在指定位置前插入节点

根据目标进行链接即可

void list_insert(listnode*pos,LTDateType x)
//目标位置,和在其前面插入数据为x的节点
{
	if (pos == NULL)//传空意味着没找到目标
	{
		printf("目标不存在,操作失败\n");
		return;
	}
	listnode*newnode=buy_listnode(x);//创建新节点
	newnode->next = pos;
	newnode->prev= pos->prev;
	pos->prev->next = newnode;
	pos->prev = newnode;
}

测试代码:

void test5()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 10086);
	print_list(plist);
	listnode*pos=list_find(plist,2);
	list_insert(pos, 888);//在2之前插入888
	print_list(plist);
	list_insert(plist->next, 666);
	//在头节点前插入666,与头插效用一致
	//可以在头插中复用这个函数
	print_list(plist);
	list_insert(plist, 520);
	//在哨兵节点前插入520,与尾插效用一致
	//可以在尾插中复用这个函数
	print_list(plist);


}
int main()
{
	test5();
}

测试效果:

2.9删除指定位置节点.

void list_erase(listnode* pos)
{
	assert(pos && pos->next != pos);
    //pos为空意味着不存在,pos->next==pos意味着为哨兵节点
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
	free(pos);
}

测试代码:

void test6()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	//list_erase(plist->prev);//尾删,测试报错
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 3);
	list_pushfront(plist, 4);
	list_pushfront(plist, 5);
	print_list(plist);
	listnode* pos = list_find(plist, 2);
	list_erase(pos);//把2删除
	print_list(plist);
	list_erase(plist->next);//头删
	print_list(plist);
	list_erase(plist->prev);//尾删
	print_list(plist);
}
int main()
{
	test6();
}

测试效果:

2.10摧毁链表

void destory_list(listnode* phead)
{
	listnode* tail = phead->prev;
	while (tail != phead)
	{
		listnode* tmp = tail;//存储尾
		tail = tail->prev;//从后往前遍历
		free(tmp);
		//不需要管什么链接了,直接摧毁就行

	}
	free(phead);//单独摧毁
}

 测试代码:
 

void test7()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	//list_erase(plist->prev);//尾删,测试报错
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 3);
	list_pushfront(plist, 4);
	list_pushfront(plist, 5);
	destory_list(plist);
}
int main()
{
	test7();
}

测试效果:

从监视来看,确实全部释放

 三、全部代码

1.接口头文件

#pragma once//防止头文件二次引用
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDateType;
//这样创建结构体数据类型,不仅是为了和int做区分
//也是为了到时更好的替换,想换直接把int改了就行
typedef struct listnode
{
	struct listnode* prev;//存放上一个节点的地址
	struct listnode* next;//存放下一个节点的地址
	LTDateType data;//该节点存放的数据
}listnode;
listnode* buy_listnode(LTDateType x);
listnode* init_listnode(listnode* phead);
void print_list(listnode* phead);
void list_pushback(listnode* phead, LTDateType x);
void list_pushfront(listnode* phead, LTDateType x);
void list_popfront(listnode* phead);
void list_popback(listnode* phead);
listnode* list_find(listnode* phead, LTDateType x);
void list_insert(listnode* pos, LTDateType x);
void list_erase(listnode* pos);
void destory_list(listnode* phead);

2.接口实现

#define _CRT_SECURE_NO_WARNINGS 1
#include"list.h"
listnode* buy_listnode(LTDateType x)
{
	listnode*newnode=(listnode*)malloc(sizeof(listnode));
	if (newnode == NULL)
	{
		perror("buy_listnode");//错误提示
		exit(-1);//节点都没创建出来,直接退出程序
	}
	newnode->data = x;//将新节点的数据初始化成我们需要的
	newnode->next = NULL;//不清楚插入的方式,先初始化成空
	newnode->prev = NULL;
}
listnode* init_listnode(listnode* phead)
{
	phead = buy_listnode(-1);	//-1是随便给的,初始化哨兵节点中的数据为-1,代表着没意义的数据
	phead->next = phead;//初始化哨兵节点,自己指向自己
	phead->prev = phead;
	return phead;
}
void print_list(listnode* phead)
{
	assert(phead);//哨兵节点地址不可能为空
	listnode* head = phead->next;
	//哨兵位节点不存储有效数据,因此phead->next才是头节点
	printf("head<=>");//纯属美观
	while (head != phead)//当head和phead相等意味着已经遍历完一遍链表
	{
		printf("%d<=>", head->data);
		head = head->next;
	}
	printf("\n");
}
void list_pushback(listnode*phead,LTDateType x)
//尾插一个新节点,此节点存储x
{
	listnode* newnode = buy_listnode(x);
	//创建一个我们需要的新节点
	listnode* tail = phead->prev;
	//先找尾,尾很显然是哨兵位节点的上一个节点
	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}
void list_pushfront(listnode* phead, LTDateType x)
{
	listnode* head = phead->next;//找到头节点
	listnode* newnode = buy_listnode(x);//创建新节点
	head->prev = newnode;
	newnode->next = head;
	phead->next = newnode;
	newnode->prev = phead;
}
void list_popfront(listnode*phead)
{
	assert(phead);
	if (phead->next == phead)
	{
		printf("链表为空,操作失败\n");//为空就别删了
		return;
	}
	listnode* head = phead->next;//找到头节点
	phead->next = head->next;
	head->next->prev = phead;
	free(head);//链接完成,彻底删除
}
void list_popback(listnode*phead)
{
	assert(phead);
	if (phead->next == phead)
	{
		printf("链表为空,操作失败\n");//为空就别删了
		return;
	}
	listnode* tail = phead->prev;//找到尾节点
	phead->prev = tail->prev;
	tail->prev->next = phead;
	free(tail);
}
listnode* list_find(listnode* phead, LTDateType x)
//哨兵节点和目标
{
	assert(phead);
	listnode* head = phead->next;//找到头节点
	while (head!=phead)//相等意味着已经遍历完了
	{
		if (head->data == x)
		//找到目标,直接返回
		{
			return head;
		}
		head = head->next;
	}
	return NULL;//遍历完还找不到,返回空指针
}
void list_insert(listnode*pos,LTDateType x)
//目标位置,和在其前面插入数据为x的节点
{
	if (pos == NULL)//传空意味着没找到目标
	{
		printf("目标不存在,操作失败\n");
		return;
	}
	listnode*newnode=buy_listnode(x);//创建新节点
	newnode->next = pos;
	newnode->prev= pos->prev;
	pos->prev->next = newnode;
	pos->prev = newnode;
}
void list_erase(listnode* pos)
{
	assert(pos && pos->next != pos);
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
	free(pos);
}
void destory_list(listnode* phead)
{
	listnode* tail = phead->prev;
	while (tail != phead)
	{
		listnode* tmp = tail;//存储尾
		tail = tail->prev;//从后往前遍历
		free(tmp);
		//不需要管什么链接了,直接摧毁就行

	}
	free(phead);//单独摧毁
}

3.测试文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"list.h"
void test1()
{
	listnode* plist=NULL;
	plist=init_listnode(plist);
	list_pushback(plist,1);
	list_pushback(plist,2);
	list_pushback(plist,3);
	list_pushback(plist,4);
	print_list(plist);
}
void test2()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	print_list(plist);
	list_pushfront(plist, 10086);
	print_list(plist);
}
void test3()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	print_list(plist);
	list_pushfront(plist, 10086);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
}
void test4()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 10086);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
}
void test5()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 10086);
	print_list(plist);
	listnode*pos=list_find(plist,2);
	list_insert(pos, 888);//在2之前插入888
	print_list(plist);
	list_insert(plist->next, 666);
	//在头节点前插入666,与头插效用一致
	//可以在头插中复用这个函数
	print_list(plist);
	list_insert(plist, 520);
	//在哨兵节点前插入520,与尾插效用一致
	//可以在尾插中复用这个函数
	print_list(plist);
}
void test6()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	//list_erase(plist->prev);//尾删,测试报错
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 3);
	list_pushfront(plist, 4);
	list_pushfront(plist, 5);
	print_list(plist);
	listnode* pos = list_find(plist, 2);
	list_erase(pos);//把2删除
	print_list(plist);
	list_erase(plist->next);//头删
	print_list(plist);
	list_erase(plist->prev);//尾删
	print_list(plist);
}
void test7()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	//list_erase(plist->prev);//尾删,测试报错
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 3);
	list_pushfront(plist, 4);
	list_pushfront(plist, 5);
	destory_list(plist);
}
int main()
{
	test7();
}

好了,今天的分享到这里就结束了,感谢各位友友来访,祝各位友友前程似锦O(∩_∩)O

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

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

相关文章

Vue3_04_ref 函数和 reactive 函数

ref 函数 声明变量时&#xff0c;赋值的值要写在 ref() 函数中修改变量时&#xff0c;变量名.value xxx在模板中使用时可以省略掉 .value&#xff0c;直接使用变量名即可 <template><h1>一个人的信息</h1><h2>姓名&#xff1a;{{name}}</h2><…

pjsip、pjsua2+bcg729 windows下编译java版本

文章目录 简要说明流程步骤 简要说明 基本参考的这里 https://docs.pjsip.org/en/latest/get-started/windows/build_instructions.html#building-the-projects 我这里主要是为了生成pjsua2.dll 用于在java下调用。 其中 libbcg729.dll 是通过vcpkg来进行安装。 pjsip使用vs2…

【Autoresizing案例03-通过代码设置Autoresizing Objective-C语言】

一、通过代码实现Autoresizing 1.好,那么,接下来,我们就给大家看一下,怎么来通过代码实现Autoresizing, 好,那么,接下来,我们为什么要说这个通过代码,实现Autoresizing, 那么,注意,我们能通过我们的storyboard来操作,就不要通过代码来实现, 以后的趋势,就是苹…

使用Git在GitHub上部署静态页面

在GitHub中&#xff0c;我们可以将自己的静态页面部署到GitHub中&#xff0c;它会给我们提供一个地址使得我们的页面变成一个真正的网站&#xff0c;可以供用户访问。 一、在GitHub下创建仓库 二、将项目部署到GitHub上 1. 初始化Git仓库 2. 提交代码 3. 关联远程仓库 在Gi…

Vulnhub: BlueMoon: 2021靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.174 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.174 80端口目录爆破&#xff0c;发现文件&#xff1a;hidden_text gobuster dir -u http://192.168.111.174 -w /usr/sha…

二重积分1

目录 二重积分 二重积分的性质 ​编辑 中值定理 二重积分的计算 方法1&#xff1a;利用直角坐标计算 方法2&#xff1a;利用极坐标进行计算 适用于极坐标的二重积分的特征 对称性和奇偶性的应用 题目 例题1&#xff1a; 题目2&#xff1a; 题目3&#xff1a; 题目4&#x…

【Spring框架】Spring AOP

目录 什么是AOP&#xff1f;AOP组成Spring AOP 实现步骤Spring AOP实现原理JDK Proxy VS CGLIB 什么是AOP&#xff1f; AOP&#xff08;Aspect Oriented Programming&#xff09;&#xff1a;⾯向切⾯编程&#xff0c;它是⼀种思想&#xff0c;它是对某⼀类事情的集中处理。⽐如…

C++11的range-based for loop(基于范围的循环)

2023年8月3日&#xff0c;周四上午 目录 语法举例说明 语法 for(能存放容器元素的变量:容器){//函数体 } 容器可以是数组、CSTL容器等 这个变量会自动遍历容器里面的每个元素 举例说明 #include<vector> #include<iostream>int main(){/*--------------------…

innovus: 让ndr使用自定义via def

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 让ndr 使用指定via def可以用add_ndr -via命令&#xff0c;如果现有的via list无法满足要求&#xff0c;可以用 add_via_definition -via_rule -row_col去创建。

跨境电商代运营模式,Live Market打造跨境电商出海SaaS服务平台

近年来&#xff0c;我国跨境电商发展取得可喜进展。商务部数据显示&#xff0c;跨境电商货物进出口规模占外贸比重由5年前的不足1%上升到目前的5%左右。私域流量业态在电商领域兴起&#xff0c;品牌企业在线上建立自主经营的手机应用软件直接触达用户。跨境电商的发展模式转向平…

如何在群晖nas中使用cpolar内网穿透?

如何在群晖nas中使用cpolar内网穿透 文章目录 如何在群晖nas中使用cpolar内网穿透 今天&#xff0c;我们来为大家介绍&#xff0c;如何在群晖系统中&#xff0c;使用图形化界面的cpolar。 cpolar经过图形化改造后&#xff0c;使用方法已经简便了很多&#xff0c;基本与其他应用…

Linux2.6.32.2内核在mini2440上的移植(七)添加ADC驱动

Linux-2.6.32.2内核在mini2440上的移植(七)---添加ADC驱动 【2】在内核中添加ADC 驱动 Linux-2.6.32.2 内核并没有提供支持S3C2440 的ADC 驱动程序&#xff0c;由于《移植开发实战指南》中ADC部分代码在实际测试中始终输出-1&#xff0c;而无法通过测试&#xff0c;于是结合…

离散Hopfield神经网络的联想记忆与matlab实现

1案例背景 1.1离散Hopfield神经网络概述 Hopfield网络作为一种全连接型的神经网络,曾经为人工神经网络的发展开辟了新的研究途径。它利用与阶层型神经网络不同的结构特征和学习方法,模拟生物神经网络的记忆机理,获得了令人满意的结果。这一网络及学习算法最初是由美国物理学家…

01背包详解(二维到一维)

有 N件物品和一个容量为 V 的背包&#xff0c;每件物品有各自的价值且只能被选择一次&#xff0c;要求在有限的背包容量下&#xff0c;装入的物品总价值最大。「0-1 背包」是较为简单的动态规划问题&#xff0c;也是其余背包问题的基础。 动态规划是不断决策求最优解的过程&am…

基于Stm32的宠物自动喂食装置(包含::论文、代码、外文原文、外文翻译、手册、建模、答辩PPT、原理图等 )

基于Stm32的宠物自动喂食装置 目录 基于Stm32的宠物自动喂食装置 一、Solidworks建模部分 装置外壳 二、TLink物联网平台 1.TLINK平台配置 2.TLINK平台的功能 &#xff08;2&#xff09;定时发送指令 &#xff08;3&#xff09;自动报警 三、Stm32控制部分 1.整体流程图…

STM32 DHT11

DHT11 DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。 使用单总线通信 该传感器包括一个电容式感湿元件和一个NTC测温元件&#xff0c;并于一个高性能8位单片机相连&#xff08;模数转换&#xff09;。 DHT11引脚说明 开漏模式下没有输出高电平的能…

代码调试2:coco数据集生成深度图

代码调试:coco数据集生成深度图 作者:安静到无声 个人主页 问题1:图片存在异常,跳过不处理 在获取深度图的时候,直接执代码,会产生以下错误:RuntimeError和ValueError。 因此我重新修改了代码,如果出现以下两种错误,则执行下一次循环,代码如下: 修改之后代码可以…

Day11-Webpack前端工程化开发

Webpack 一 webpack基本概念 遇到问题 开发中希望将文件分开来编写,比如CSS代码,可以分为头部尾部内容,公共的样式。 JS代码也希望拆分为多个文件,分别引入,以后代码比较好维护。 本地图片,希望可以实现小图片不用访问后端,保存在前端代码中就可以了 运行程序时我…

火山引擎DataLeap的Data Catalog系统搜索实践 (上)

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 摘要 火山引擎大数据研发治理套件 DataLeap的Data Catalog系统通过汇总和组织各种元数据&#xff0c;解决了数据生产者梳理数据、数据消费者找数和理解数的业务场景…

生产事故-记一次特殊的OOM排查

0x01 事故背景 2023年3月10日14时19分&#xff0c;C公司开发人员向A公司开发人员反映某开放接口从2023年3月10日14时许开始无法访问和使用。该系统为某基础数据接口服务&#xff0c;基于 HTTP 协议进行通信。按照惯例&#xff0c;首先排查网络是否异常&#xff0c;经运维人员检…