单链表的相关操作(初阶--寥寥万字不成敬意)

目录

链表的概念

链表的相关操作:

链表的创建:

打印链表:

申请新节点:

链表的尾插:

 !!!对于传参中二级指针的解释:

链表的头插:

链表的尾删: 

链表的头删:

寻找结点:

在链表的指定位置前插入:

在链表的指定位置后插入:

删除pos位置的结点:

删除pos位置后的结点:

销毁链表:

最终结果:

SList.h文件:

SList.c文件:

test.c文件:


链表的概念

        链表是线性表的一种,它是⼀种物理存储结构上⾮连续、⾮顺序的存储结构,数据元素的逻

辑顺序是通过链表中的指针链接次序实现的 。其实链表就相当于一列火车:

        链表的结构跟⽕⻋⻋厢相似,淡季⻋厢会相应减少,旺季时⻋厢会额外增加,减少和增加车厢并不会影响其它车厢,每节⻋厢都是独⽴存在的。且每节⻋厢都有⻋⻔。
        假设每节⻋厢的⻋⻔都被锁上,且打开这些车厢所需要的钥匙各不相同,那么如果乘务员从第一节车厢开始向后面的车厢走去,如何从⻋头⾛到⻋尾?
答案:每节⻋厢⾥都放⼀把下⼀节⻋厢的钥匙。
而每节车厢里面肯定是有人或者货物的,所以这就引申出了一条新的概念:在链表⾥,每节“⻋厢”是由 下一个车厢的🔑 本节车厢中存储的“数据" 组成的。

!!当你对后续的链表内容有问题,请重新回来仔细观看下图!!
!!当你对后续的链表内容有问题,请重新回来仔细观看上图!!

与顺序表不同的是,链表⾥的每节"⻋厢"都是独⽴申请下来的空间,我们称之为“ 结点/节点 ”。
结点 =  当前节点中保存的数据data + 保存下⼀个节点地址的指针变量next
        有了车厢,我们就需要有一节火车头来带动这些车厢,链表中的火车头就是 头结点(头结点不存储数据),指向链表的第一个有效结点(存储数据)的地址,在这里plist就为头结点
为什么需要指针变量来保存下⼀个节点的位置?
        因为链表在内存空间上的存储是非连续的 ,就和火车车厢一样,根据需求进行增加和删除,通俗来讲就是,用到你这块儿了我用指针(火车挂钩)给你连上你就得给我进链表不用你的时候把脸上你的指针(火车挂钩)断开你就一边闲着去。

链表的相关操作:

以下链表内容为不带头单向不循环链表

链表的创建:

创建链表需要经历以下操作:

1、定义一个结构体来表示链表的结点(SList.h文件)

//定义一种链表节点的结构(实际应用中有多种,这里只演示最基本的结构)
typedef int SLDataType; //便于切换链表中存储数据的类型
struct SListNode {   SLDataType data;  //存储数据struct SListNode* next;  //用来保存下一个节点地址的指针变量next
};
typedef struct SListNode SLNode;  //将链表结点的结构体重命名为SLNode
2、编写创建链表的函数(第二点这里的 内容只是为了方便理解后续内容,具体情况请看下面的实际操作,有个简单的了解)
该函数主要进行的操作是:        
①创建新节点并为其开辟内存空间
②将新结点的next指针指向下一个结点
//申请结点函数
void slttest()
{SLNode* node1 = (SLNode*)malloc(sizeof(SLNode)); node1->data = 1;SLNode* node2 = (SLNode*)malloc(sizeof(SLNode));node2->data = 2;SLNode* node3 = (SLNode*)malloc(sizeof(SLNode));node3->data = 3;SLNode* node4 = (SLNode*)malloc(sizeof(SLNode));node4->data = 4;node1->next = node2;node2->next = node3;node3->next = node4;node4->next = NULL;//打印链表SLNode* plist = node1;  SLPrint(plist);
}

打印链表:

//用phead表示头结点,它指向链表的第一个结点(如果思路出现混乱,一定要再看一边前面的链表图)
void SLPrint(SLNode* phead) 
{	//循环打印//为了能在遍历后仍能找到刚开始的起点,我们就需要利用一个临时指针pcur来存储头结点的地址SLNode* pcur = phead;//当头结点不为空时进行循环while (pcur){//打印此时所处结点中的数据printf("%d ->", pcur->data);//打印结束后让pcur指向下一个结点的地址pcur = pcur->next;}//到最后时现有结点遍历完成,空间为NULLprintf("NULL\n");
}

申请新节点:

//申请有效结点函数(并在该结点中存储数据)
SLNode* SLByNode(SLDataType x) 
{//为链表的新结点申请一个新的空间SLNode* node = (SLNode*)malloc(sizeof(SLNode));//该节点中存储的数据为xnode->data = x;//将该结点的下一个结点置为空,因为我们也不知道它后面到底还要不要结点了node->next = NULL;//返回申请的新结点return node;
}

链表的尾插:

//链表的尾插
void SLPushBack(SLNode** pphead, SLDataType x)
{//判断传入的头结点plist是否为空assert(pphead);//如果存在头结点则进行后续操作//先申请一个新的有效结点SLNode* node = SLByNode(x);//如果第一个有效结点为空,则令*pphead指向新创建的有效结点if (*pphead == NULL){*pphead = node;return;}//如果第一个有效结点不为空,则通过循环读取至链表的结尾//先定义一个临时的指针变量pcur,令pcur指向第一个有效结点SLNode* pcur = *pphead;//然后利用pcur->next遍历至链表的末尾while (pcur->next){pcur = pcur->next;}//当遍历至链表的末尾时,让pcur指向新的有效结点pcur->next = node;
}

 !!!对于传参中二级指针的解释:

//pphead是一个二级指针,通过判断它的非空情况可以得到整个链表是否存在
&plist (获取的是plist这个指针的地址)==  pphead//对于pphead的解引用
plist(头结点的地址) == *pphead
如果第一个结点为空那么该结点的地址为空//对于*pphead的解引用,得到头节点中的地址
*plist(第一个结点的内存块)== **pphead

链表的头插:

//链表的头插
void SLPushFront(SLNode** pphead, SLDataType x)//相当于两个互相赋值
{//判断传入的头结点plist是否为空assert(pphead);SLNode* node = SLByNode(x);//下面两条进行的其实就是简单的交接工作//先将当前头指针指向的结点交给了node->nextnode->next = *pphead;//然后让头指针指向新节点的地址*pphead = node;
}

链表的尾删: 

//链表的尾删(链表为空的情况下不能尾删)
void SLPopBack(SLNode** pphead)
{    //判断传入的头结点plist是否为空assert(pphead);//判断第一个有效结点是否为空,链表为空不能进行尾删assert(*pphead);//当有且只有一个有效结点时if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{//当不止一个有效结点时//未防止删除后空指针的出现,在寻找尾节点的时候我们也要找到尾节点的前一个节点//找尾结点和尾结点的前一个结点//定义prev为尾结点的前一个结点SLNode* prev = NULL;//定义ptai为用于找尾结点的指针,先让它接收第一个有效结点的地址SLNode* ptail = *pphead;while (ptail->next != NULL){//先令prev将ptail保存下来,当ptail->next为空时(此时到达尾指针)就不会进入循环将ptail    //存入prev中,此时prev保存的就是尾结点的前一个结点prev = ptail;ptail = ptail->next;}//此时prev(尾结点的前一个结点)的next指针不再指向ptail(尾结点)而是指向ptail的下一个结点prev->next = ptail->next;free(ptail);ptail = NULL;}
}

链表的头删:

//链表的头删
void SLPopPront(SLNode** pphead)
{//判断传入的头结点plist是否为空assert(pphead);//判断第一个有效结点是否为空,链表为空不能进行尾删assert(*pphead);//当有且只有一个有效结点时if ((*pphead)->next == NULL){//直接把头结点删除free(*pphead);*pphead = NULL;}//当整个链表//使用临时指针指向头结点SLNode* del = *pphead;//令头结点指向新的头结点*pphead = (*pphead)->next;//将临时指针指向的结点(头结点)释放掉free(del);del = NULL;
}

寻找结点:

//查找结点
SLNode* SLFind(SLNode** pphead, SLDataType x)
{//判断传入的头结点plist是否为空assert(pphead);SLNode* pcur = *pphead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}//该函数需要与在指定位置插入删除结合,返回的结果使用一个指针来接收,在test.c文件中的使用情况如下:
SLNode* find = SLFind(&plist,2);//查找数据为2的结点
SLInsert(&plist,find,x)//在find(数据为2)的结点前插入含有数据x的新节点

在完成以下代码后需要考虑的三种情况:

1、pos是头结点

2、pos是中间结点

3、pos是最后一个结点

在链表的指定位置前插入:

//在指定位置之前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x)
{//判断传入的头结点plist是否为空assert(pphead);//约定链表不能为空,pos也不能为空assert(pos);assert(*pphead);SLNode* node = SLByNode(x);//有且只有一个有效结点,此时在该有效结点前进行插入操作就相当于头插if(pos == *pphead){node->next = *pphead;*pphead = node;return;}//当不只有一个有效结点的时候,先通过循环找到pos的前一个结点SLNode* prev = *pphead; //当prev->next指向pos的时候跳出循环while (prev->next != pos){prev = prev->next;}//此时循环结束,prev指向pos//最后,处理插入位置两边的结点与新结点三者之间的关系prve node pos//此时下面的两个操作顺序可以交换node->next = pos;prev->next = node;
}

在链表的指定位置后插入:

//在指定位置之后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x)
{//确定能找到该结点assert(pos);SLNode* node = SLByNode(x);//pos node pos->nextnode->next = pos->next;pos->next = pos;
}//使用案例:
//SLNode* find = SLFind(&plist,1);
//SLInsertAfter(find,100);

删除pos位置的结点:

//删除pos结点
void SLErase(SLNode** pphead, SLNode* pos)
{assert(pphead);assert(*pphead);assert(pos);//当pos为第一个有效结点时if (pos == *pphead){*pphead = (*pphead)->next;free(pos);return;}//当pos不为第一个有效结点时//先找到pos的前一个结点,然后(后续内容与之前的操作类似)SLNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//先完成pos两边结点的交接工作,然后再释放pos结点prev->next = pos->next;free(pos);pos = NULL;
}

删除pos位置后的结点:

//删除pos结点之后的数据
void SLEraseAfter(SLNode* pos)
{//除了pos不为空以外,还需要pos->next不为空,因为pos刚好是最后一个结点你总不能删除一个NULLassert(pos && pos->next);SLNode* del = pos->next;pos->next = del->next;free(del);
}

销毁链表:

//销毁链表
void SLDestroy(SLNode** pphead)
{assert(pphead);SLNode* pcur = *pphead;//循环删除while (pcur){SLNode* next = pcur->next;free(pcur);pcur = next;}//此时链表所有的有效结点已经结束了,最后将头结点置为空即可*pphead = NULL;
}

最终结果:

SList.h文件:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>//定义链表节点的结构
typedef int SLDataType;
struct SListNode {   //定义一个表示链表节点的结构体SLDataType data;  //链表中用于存储数据的成员(某个节点的数据)struct SListNode* next;  //用来保存下一个节点地址的指针变量next
};
typedef struct SListNode SLNode;  //将指向下一个节点的指针类型重命名为SLNode//创建几个结点组成的链表,并打印链表
void SLPrint(SLNode* phead);  
//链表的尾插
void SLPushBack(SLNode** phead, SLDataType x);
//链表的头插
void SLPushFront(SLNode** phead, SLDataType x);
//链表的尾删
void SLPopBack(SLNode** pphead);
//链表的头删
void SLPopPront(SLNode** pphead);
//找结点,这里传一级指针实际上就可以了,因为不改变头节点,但是这里还是要写成二级指针,因为要保证接口一致性
SLNode* SLFind(SLNode** pphead,SLDataType x);//链表的在指定位置之前插入
void SLInsert(SLNode** phead, SLNode* pos,SLDataType x);
//链表的指定位置删除
void SLInsertAfter(SLNode* pos, SLDataType x);//此时不需要第一个参数
//删除pos位置的结点
void SLErase(SLNode** pphead, SLNode* pos);
//删除pos后的结点
void SLEraseAfter(SLNode* pos);
//销毁链表
void SLDestroy(SLNode** pphead);

SList.c文件:

#include "SList.h"
//用phead表示头结点,它指向链表的第一个结点(如果思路出现混乱,一定要再看一边前面的链表图)
void SLPrint(SLNode* phead)
{//循环打印//为了能在遍历后仍能找到刚开始的起点,我们就需要利用一个临时指针pcur来存储头结点的地址SLNode* pcur = phead;//当头结点不为空时进行循环while (pcur){//打印此时所处结点中的数据printf("%d ->", pcur->data);//打印结束后让pcur指向下一个结点的地址pcur = pcur->next;}//到最后时现有结点遍历完成,空间为NULLprintf("NULL\n");
}//申请有效结点函数(并在该结点中存储数据)
SLNode* SLByNode(SLDataType x)
{//为链表的新结点申请一个新的空间SLNode* node = (SLNode*)malloc(sizeof(SLNode));//该节点中存储的数据为xnode->data = x;//将该结点的下一个结点置为空,因为我们也不知道它后面到底还要不要结点了node->next = NULL;//返回申请的新结点return node;
}//链表的尾插
void SLPushBack(SLNode** pphead, SLDataType x)
{//判断传入的头结点plist是否为空assert(pphead);//如果存在头结点则进行后续操作//先申请一个新的有效结点SLNode* node = SLByNode(x);//如果第一个有效结点为空,则令*pphead指向新创建的有效结点if (*pphead == NULL){*pphead = node;return;}//如果第一个有效结点不为空,则通过循环读取至链表的结尾//先定义一个临时的指针变量pcur,令pcur指向第一个有效结点SLNode* pcur = *pphead;//然后利用pcur->next遍历至链表的末尾while (pcur->next){pcur = pcur->next;}//当遍历至链表的末尾时,让pcur指向新的有效结点pcur->next = node;
}//链表的头插
void SLPushFront(SLNode** pphead, SLDataType x)//相当于两个互相赋值
{//判断传入的头结点plist是否为空assert(pphead);SLNode* node = SLByNode(x);//下面两条进行的其实就是简单的交接工作//先将当前头指针指向的结点交给了node->nextnode->next = *pphead;//然后让头指针指向新节点的地址*pphead = node;
}//链表的尾删(链表为空的情况下不能尾删)
void SLPopBack(SLNode** pphead)
{//判断传入的头结点plist是否为空assert(pphead);//判断第一个有效结点是否为空,链表为空不能进行尾删assert(*pphead);//当有且只有一个有效结点时if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}//当不止一个有效结点时//未防止删除后空指针的出现,在寻找尾节点的时候我们也要找到尾节点的前一个节点//找尾结点和尾结点的前一个结点//定义prev为尾结点的前一个结点else{SLNode* prev = NULL;//定义ptai为用于找尾结点的指针,先让它接收第一个有效结点的地址SLNode* ptail = *pphead;while (ptail->next != NULL){//先令prev将ptail保存下来,当ptail->next为空时(此时到达尾指针)就不会进入循环将ptail    //存入prev中,此时prev保存的就是尾结点的前一个结点prev = ptail;ptail = ptail->next;}//此时prev(尾结点的前一个结点)的next指针不再指向ptail(尾结点)而是指向ptail的下一个结点prev->next = ptail->next;free(ptail);ptail = NULL;}
}//链表的头删
void SLPopPront(SLNode** pphead)
{//判断传入的头结点plist是否为空assert(pphead);//判断第一个有效结点是否为空,链表为空不能进行尾删assert(*pphead);//当有且只有一个有效结点时if ((*pphead)->next == NULL){//直接把头结点删除free(*pphead);*pphead = NULL;}//当整个链表//使用临时指针指向头结点SLNode* del = *pphead;//令头结点指向新的头结点*pphead = (*pphead)->next;//将临时指针指向的结点(头结点)释放掉free(del);del = NULL;
}//查找结点
SLNode* SLFind(SLNode** pphead, SLDataType x)
{//判断传入的头结点plist是否为空assert(pphead);SLNode* pcur = *pphead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}
//
该函数需要与在指定位置插入删除结合,返回的结果使用一个指针来接收,在test.c文件中的使用情况如下:
//SLNode* find = SLFind(&plist, 2);//查找数据为2的结点
//SLInsert(&plist, find, x)//在find(数据为2)的结点前插入含有数据x的新节点//在指定位置之前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x)
{//判断传入的头结点plist是否为空assert(pphead);//约定链表不能为空,pos也不能为空assert(pos);assert(*pphead);SLNode* node = SLByNode(x);//有且只有一个有效结点,此时在该有效结点前进行插入操作就相当于头插if (pos == *pphead){node->next = *pphead;*pphead = node;return;}//当不只有一个有效结点的时候,先通过循环找到pos的前一个结点SLNode* prev = *pphead;//当prev->next指向pos的时候跳出循环while (prev->next != pos){prev = prev->next;}//此时循环结束,prev指向pos//最后,处理插入位置两边的结点与新结点三者之间的关系prve node pos//此时下面的两个操作顺序可以交换node->next = pos;prev->next = node;
}//在指定位置之后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x)
{//确定能找到该结点assert(pos);SLNode* node = SLByNode(x);//pos node pos->nextnode->next = pos->next;pos->next = pos;
}//使用案例:
//SLNode* find = SLFind(&plist,1);
//SLInsertAfter(find,100);//删除pos结点
void SLErase(SLNode** pphead, SLNode* pos)
{assert(pphead);assert(*pphead);assert(pos);//当pos为第一个有效结点时if (pos == *pphead){*pphead = (*pphead)->next;free(pos);return;}//当pos不为第一个有效结点时//先找到pos的前一个结点,然后(后续内容与之前的操作类似)SLNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//先完成pos两边结点的交接工作,然后再释放pos结点prev->next = pos->next;free(pos);pos = NULL;
}//销毁链表
void SLDestroy(SLNode** pphead)
{assert(pphead);SLNode* pcur = *pphead;//循环删除while (pcur){SLNode* next = pcur->next;free(pcur);pcur = next;}//此时链表所有的有效结点已经结束了,最后将头结点置为空即可*pphead = NULL;
}

test.c文件:

#include "SList.h"
//申请结点函数
//void slttest()
//{
//	//使用malloc函数动态分配,创建链表的头节点,它不包含任何数据,知识用来指向链表的第一个实际节点
//	SLNode* node1 = (SLNode*)malloc(sizeof(SLNode)); 
//	//head
//	node1->data = 1;
//	SLNode* node2 = (SLNode*)malloc(sizeof(SLNode));
//	node2->data = 2;
//	SLNode* node3 = (SLNode*)malloc(sizeof(SLNode));
//	node3->data = 3;
//	SLNode* node4 = (SLNode*)malloc(sizeof(SLNode));
//	node4->data = 4;
//
//	//实现四个节点的链接
//	//初始化头节点的next指针为node2指针变量
//	node1->next = node2;
//	node2->next = node3;
//	node3->next = node4;
//	node4->next = NULL;
//
//	//打印链表
//	SLNode* plist = node1;  //定义一个SLNode*类型的指针变量plist,他也叫头指针,我们用它指向链表的头节点
//	
//	//注意头节点和头指针的概念是不同的:
//	/*在链表的上下文中,通常将链表的第一个节点称为头节点(Head Node),但是头节点和头指针(Head Pointer)是不同的概念。
//	头节点是链表中的第一个实际节点,它包含数据和指向下一个节点的指针。头节点是链表的起始点,它可以存储实际的数据,也可以只是一个占位符节点,不存储实际的数据。
//	头指针是指向链表的头节点的指针。它是一个指针变量,存储着头节点的地址。通过头指针,我们可以访问链表中的每个节点,或者进行其他链表操作。
//	因此,头节点是链表中的一个节点,而头指针是指向头节点的指针。它们是不同的概念,但在某些情况下,人们可能会将它们混用或将它们视为相同的概念,因为头节点通常通过头指针来访问。*/
//	
//	SLNPrint(plist);
//}void slttest()
{SLNode* plist = NULL;	//尾插SLPushBack(&plist, 1);  SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPushBack(&plist, 4);//1->2->3->4->NULLSLPrint(plist);头插//SLPushFront(&plist, 1);//SLPushFront(&plist, 2);//SLPushFront(&plist, 3);//SLPushFront(&plist, 4);//4->3->2->1->NULL//SLPrint(plist);//尾删SLPopBack(&plist);SLPopBack(&plist);SLPopBack(&plist);头删//SLPopPront(&plist);//SLPopPront(&plist);//SLPopPront(&plist);//SLPopPront(&plist);//SLPopPront(&plist);//SLPopPront(&plist);指定位置插入//SLNode* find = SLFind(&plist, 4);//SLInsert(&plist, find,11);//1->11->2->3->4->NULL在指定位置之后插入数据//SLInsertAfter(find, 100);删除pos位置的节点//SLErase(&plist, find);//1->2->3->NULL删除pos之后的节点//SLEraseAfter(find);////销毁链表//SLDestory(&plist);//检验是否成功销毁SLPrint(plist);
}int main()
{slttest();return 0;
}

注意事项:

1、判断条件的等号都是==

2、冒号是否写了

3、函数或者指针变量的名字是否书写正确 

4、最后的test.c文件实验时可能会存在一些多删之类的问题(函数写多了)请自行检查~

如果还有其它你编写时出现的错误也可以说一下~ 

~over~

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

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

相关文章

保护隐私就是在保护自己!如何在Android上更改应用程序权限

如果你关心隐私&#xff0c;知道如何在Android上更改应用程序权限将成为一项非常重要的技能。即使是最好的安卓应用程序也可以对手机的功能和数据进行广泛的访问&#xff0c;因此准确控制它们的使用范围会有所帮助。 一旦你在手机上加载了应用程序&#xff0c;你可能会注意到它…

【LeetCode】35. 搜索插入位置

1 问题 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2 示例…

在线课堂知识系统源码系统+前端+后端完整搭建教程

大家好啊&#xff0c;今天罗峰来给大家分享一款在线课堂知识系统源码系统。这款系统的功能十分强大。可以使用手机随时随地地学习&#xff0c;有专业的导师答疑解惑。支持视频&#xff0c;音频&#xff0c;图文章节。以下是部分核心代码图&#xff1a; 系统特色功能一览&#x…

Linux上Docker的安装以及作为非运维人员应当掌握哪些Docker命令

目录 前言 1、安装步骤 2、理解镜像和容器究竟是什么意思 2.1、为什么我们要知道什么是镜像&#xff0c;什么是容器&#xff1f; 2.2、什么是镜像&#xff1f; 2.3、什么是容器&#xff1f; 2.4、Docker在做什么&#xff1f; 2.5、什么是镜像仓库&#xff1f; 2、Dock…

AN动画基础——缓动动画

【AN动画基础——影片剪辑滤镜】 基础动画缓动动画缓动原理实例应用 本篇内容&#xff1a;了解曲线原理 重点内容&#xff1a;缓动动画 工 具&#xff1a;Adobe Animate 2022 基础动画 我们先做一个非缓动的效果的动画。 绘制一个矩形设置成元件—图形&#xff0c;30帧插入关…

论文阅读 Memory Enhanced Global-Local Aggregation for Video Object Detection

Memory Enhanced Global-Local Aggregation for Video Object Detection Abstract 人类如何识别视频中的物体&#xff1f;由于单一帧的质量低下&#xff0c;仅仅利用一帧图像内的信息可能很难让人们在这一帧中识别被遮挡的物体。我们认为人们识别视频中的物体有两个重要线索&…

C# 取消一个不带CancellationToken的任务?

在异步函数中&#xff0c;一般使用CancellationToken来控制函数的执行。这个Token需要作为参数传递到异步函数中&#xff1a; public staic Task<T> DoAsync(CancellationToken token) {... } 那么如果一个异步函数没有这个Token参数&#xff0c;如何取消呢? 之前看到一…

TODO Vue typescript forEach的bug,需要再核實

forEach 一個string[]&#xff0c;只有最後一個匹配條件有效&#xff0c;其它條件無效。 所以&#xff0c;只能替換成普通的for循環。 console.log(taskList)// for (const _task of taskList.value) {// if (_task invoiceSendEmail) {// form.value.invoiceSendEmail…

Hadoop3教程(十五):MapReduce中的Combiner

文章目录 &#xff08;103&#xff09;Combiner概述什么是CombinerCombiner有什么用处Combiner有什么特点如何自定义Combiner &#xff08;104&#xff09;Combiner合并案例实操如何从日志里查看Combiner如果不存在Reduce阶段&#xff0c;会发生什么自定义Combiner的两种方式 参…

【非root用户、CentOS系统】中使用源码安装gcc/g++的教程

1.引言 系统&#xff1a;CentOS-7.9 显卡驱动版本&#xff1a;460 CUDA Version: 11.2 &#x1f33c;基于本地环境选择安装gcc-10.1.0 &#x1f449; gcc下载网址 2.安装说明 下载好对应的gcc的安装包并解压&#xff1a; 打开gcc-10.1.0/contrib/download_prerequisites&#…

关于gt_sampling的理解

pcdet/datasets/augmentor/data_augmentor.py def gt_sampling(self, configNone):db_sampler database_sampler.DataBaseSampler(root_pathself.root_path,sampler_cfgconfig,class_namesself.class_names,loggerself.logger)return db_sampler此函数指向DataBaseSampler类&a…

0基础学习VR全景平台篇第109篇:认识拼接软件PTGui Pro

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01;今天给大家讲解我们全景后期拼接软件PTgui pro&#xff0c;下面我们开始吧&#xff01; &#xff08;PTgui pro软件课程大纲&#xff09; 1.PTGui这个软件是什么 发明人 &#xf…

【网络编程】从网络编程、TCP/IP开始到BIO、NIO入门知识(未完待续...)

目录 前言前置知识一、计算机网络体系结构二、TCP/IP协议族2.1 简介*2.2 TCP/IP网络传输中的数据2.3 地址和端口号2.4 小总结 三、TCP/UDP特性3.1 TCP特性TCP 3次握手TCP 4次挥手TCP头部结构体 3.2 UDP特性 四、总结 课程内容一、网络通信编程基础知识1.1 什么是Socket1.2 长连…

Python之旅----判断语句

布尔类型和比较运算符 布尔类型 布尔类型的定义 布尔类型的字面量&#xff1a; True 表示真&#xff08;是、肯定&#xff09; False 表示假 &#xff08;否、否定&#xff09; 也就是布尔类型进行判断&#xff0c;只会有2个结果&#xff1a;是或否 定义变量存储布尔类型…

天猫店铺商品评论数据采集,天猫商品评论数据接口,天猫API接口

天猫店铺商品评论数据接口可以获取到商品ID&#xff0c;商品标题&#xff0c;商品优惠券&#xff0c;商品到手价&#xff0c;商品价格&#xff0c;商品优惠价&#xff0c;商品sku属性&#xff0c;商品图片&#xff0c;商品视频&#xff0c;商品sku属性图片&#xff0c;商品属性…

ant中的environment属性

在ant的配置文件中&#xff0c;可以设置属性environment的值&#xff0c;设置的这个值就作为访问环境变量的前缀。例如声明了environment“env”&#xff0c;那么就可以通过env.<环境变量名称>来访问环境变量。 例如创建了一个Java工程&#xff0c;在工程目录下有一个bu…

HCIA --- VLAN实验配置

一、各交换机上配置&#xff1a; 1、各交换机上创建VLAN 2、交换机上的各个接口划分到对应的VLAN中 3、将与交换机、路由器相连的接口创建trunk干道 SW1&#xff1a; [sw1]vlan batch 2 to 3 批量创建VLAN2-3 [sw1]interface Ethernet0/0/1 单独将某个接口划分到对应…

信息保卫战:揭秘迅软DSE护航企业免受泄密之害

随着网络技术的发展&#xff0c;通过网络应用如网盘、网页、邮件、即时通讯工具传输分享文件变得越来越多&#xff0c;这些工具传输速度快&#xff0c;能够将大容量的文档快速传送给他人&#xff0c;在工作中受到许多人的青睐。 然而由这些传输工具引发的泄密事件也不断增多&am…

视频怎么压缩?视频太大这样处理变小

在当今时代&#xff0c;视频已经成为了我们日常生活中不可或缺的一部分&#xff0c;然而&#xff0c;视频文件往往非常大&#xff0c;给我们的存储和传输带来了很大的不便&#xff0c;那么&#xff0c;如何有效地压缩视频呢&#xff1f; 一、使用压缩软件 首先我们给大家分享一…

供应商工厂突发爆炸,日本丰田7座工厂停工 | 百能云芯

根据日本共同社的最新报导&#xff0c;日本著名汽车制造商丰田汽车近期遭遇了一系列生产中断问题。这次生产中断的根本原因在于供应商公司发生了一起爆炸事件&#xff0c;导致零部件供应链受到了严重干扰&#xff0c;迫使丰田暂时停工。截至目前&#xff0c;这一事件已经影响了…