数据结构:线性表(详解)

news2024/10/4 23:46:01

线性表

线性表的知识框架:

线性表的定义:

线性表是具有相同数据类型的n(n > 0)个数据元素的有限序列,当n = 0时线性表为一个空表。
若用L命名为线性表,则
数据集合为L= {a1,a2,…,an},其中a1称为表头元素,an称为表尾元素。除第一个元素外,每个元素有且仅有一个直接前驱。除最后一个元素外,每个元素有且仅有一个直接后继。

线性表的特点:

1.表中元素的个数有限
2.表中元素具有逻辑上的顺序表,表中元素有其先后次序
3.表中元素都是数据元素,每个元素都是单个元素
4.表中元素的数据类型相同,所以每个元素占有相同大小的存储空间
5.线性表是一种逻辑结构,表示元素之间一对一的相邻关系。顺序表和链表是指存储结构

线性表的顺序存储结构

顺序表的的定义:

线性表的顺序存储又称顺序表。它是用一组地址连续的存储单元依次存储线性表中的数据元素。

顺序表的特点:

1.顺序表的存储密度高,每个结点只存储数据结构。
2.顺序表逻辑上相邻的元素在物理上也相邻,所以插入和删除操作需要移动大量数据
3.顺序表是随机访问,即通过首地址和元素序号可在时间O(1)内找到指定的元素

顺序表代码实现:

    顺序表储存结构:

typedef int SLTDataType;
typedef struct SeqList
{
	SLDatatype capacity;//数组的容量
	SLDatatype size;//有效数据
	SLDatatype* arr;
}SL;
顺序表所有接口:
//初始化/销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);

//顺序表的头部/尾部插入
void SLPushBack(SL* ps, SLDatatype x);
void SLPushFront(SL* ps, SLDatatype x);

//顺序表的头部/尾部删除
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

//指定位置之前插入数据/删除指定位置数据
void SLInsert(SL* ps, SLDatatype pos, SLDatatype x);
void SLErase(SL* ps, SLDatatype pos);
顺序表初始化和销毁:
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

顺序表输出:

void SLPrint(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
    printf("\n");
}
顺序表扩容:
void SLIncreaseCapacity(SL* ps)
{
	if (ps->capacity == ps->size)//当有效数据与实际数据相等则需要扩容
	{
		SLDatatype NewCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDatatype* tmp = (SLDatatype*)realloc(ps->arr, NewCapacity * sizeof(int));
		if (tmp == NULL)
		{
			perror("malloc error");
			exit(-1);
		}
		ps->arr = tmp; //仅当 SL 结构被销毁时,用于 ps->arr 的内存才会被释放。
		ps->capacity = NewCapacity;
	}
}
顺序表尾插:
void SLPushBack(SL* ps, SLDatatype x)
{
	assert(ps);
SLIncreaseCapacity(ps);//判断是否需要扩容
ps->arr[ps->size++] = x;
}

顺序表尾插输出:

顺序表头插:
void SLPushFront(SL* ps, SLDatatype x)
{
	assert(ps);
SLIncreaseCapacity(ps);//判断是否需要扩容
for (int i = ps->size; i > 0; i--)
{
	ps->arr[i] = ps->arr[i - 1];
}
ps->arr[0] = x;
ps->size++;
}

顺序表头插输出:

顺序表尾删:
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);//判断数组是否为空
	ps->size--;//size--只是在逻辑层面删除了而已,但物理层面还是实际存在的 
               //只是我们不将它看成 顺序表的一部分,所以就可以理解为删除了         
}

顺序表尾删输出:

顺序表头删:
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

顺序表头删输出:

在指定位置插入:
void SLInsert(SL* ps, SLDatatype pos, SLDatatype x)
{
	assert(ps);
	SLCheckCapacity(ps);
	assert(pos >= 0 && pos < ps->size);//pos如果小于0那就没什么意义并且不能等于ps->size如果等于那就相当于尾插了
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

指定位置输出:

在指定位置删除:
void SLErase(SL* ps, SLDatatype pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

指定位置输出:

顺序表的优缺点:

  优点:1.空间利用率高

             2.插入删除方便

             3.结构简单

  缺点:1.访问效率低

            2.插入和删除操作可能导致元素移动

            3.难以实现部分元素的随机访问

线性表的链式存储结构:

单链表的定义:

单链表(SLL)是一种由节点序列组成的链接数据结构,每个节点包含一个数据元素和一个指向下一个节点的指针。单链表以其简单性和效率而闻名,广泛应用于各种应用程序。                                                                                  单链表结构如下:

单链表代码实现:

单链表存储结构:
typedef int SLTDataType;
typedef struct SList
{
	struct SList* next;//指针域
	SLTDataType data;//数据域
}SL;
单链表所有接口:

//链表的输出、销毁
void SLPrint(SL* phead);
void SListDesTroy(SL** pphead);

//链表的尾插、头插
void SLPushBack(SL** pphead, SLTDataType x);
void SLPushFront(SL** pphead, SLTDataType x);

//链表的尾删、头删
void SLPopBack(SL** pphead);
void SLPopFront(SL** pphead);

//查找
SL* SLTFind(SL* phead, SLTDataType x);

//在指定位置之前插入数据、之后插入数据
void SLTInsert(SL** pphead, SL* pos, SLTDataType x);
void SLTInsertAfter(SL* pos, SLTDataType x);

//删除pos节点、pos之后的节点
void SLTErase(SL** pphead, SL* pos);
void SLTEraseAfter(SL* pos);
单链表输出:

void SLPrint(SL* phead)
{
	SL* pur = phead;
	while (pur)
	{
		printf("%d->", pur->data);
		pur = pur->next;
	}
	printf("NULL");
	printf("\n");
}
单链表销毁:

void SListDesTroy(SL** pphead)
{
	void SListDesTroy(SL** pphead)
{
	assert(pphead && *pphead);
	SL* Pfast = (*pphead)->next;
	SL* Pslow = *pphead;
	while (Pslow && Pfast != NULL)
	{
		free(Pslow);
		Pslow = NULL;

		Pslow = Pfast;
		Pfast = Pfast->next;
	}
    //销毁尾节点
	free(Pslow);
	Pslow = NULL;
    //free完之后再将头节点置为空
	*pphead = NULL;
}
}

销毁链表输出:

扩容单链表空间:

SL* SLTBuyNode(SLTDataType x)
{
	SL* Newnode = (SL*)malloc(sizeof(SL));
	SL*	ptmp = Newnode;
	if (ptmp == NULL)
	{
		perror("malloc error");
		exit(-1);
	}
	Newnode->data = x;
	Newnode->next = NULL;
	return Newnode;
}
单链表尾插:

//为什么需要二级指针而不用一级指针呢,因为传一级的话改变不了它的指向而二级指针可以
//就相当于C语言里面传值和传地址一个道理
void SLPushBack(SL** pphead, SLTDataType x)
{
	//pphead:相当于指针指向节点的那个指针的地址
    //*pphead:相当于节点地址
    //**pphead:相当于节点里的数据
	assert(pphead);//判断pphead指针是否为空和节点是否为空
	//assert(*pphead);//判断pphead节点是否为空
	SL* newnode = SLTBuyNode(x);
	if (*pphead == NULL)//当链表为空时那么newnode就可以作为链表的新节点
	{
		*pphead = newnode;
		return;
	}
	//链表不为空
	SL* Ptmp = *pphead;
	while (Ptmp->next)
	{
		Ptmp = Ptmp->next;
	}
	Ptmp->next = newnode;
}

单链表尾插输出:

本质上,单指针用于“只读”操作,而双指针用于“读写”操作。

以下是一个简化的类比来说明区别:

想象一个链表就像一列火车车厢。每个车厢代表列表中的一个节点,车厢之间的连接代表指针。

单指针就像火车上的乘客。他们可以从一辆车厢移动到另一辆车厢,观察每辆车厢的内容(数据访问),但他们不能直接拆卸或连接车厢(修改列表结构)。

双指针就像火车乘务员。他们不仅有权在车厢之间移动,还可以解耦和耦合车厢,修改列车的组成(修改列表结构)。
如果还是搞不懂可以点开这个链接,这个博主写的非常好http://t.csdnimg.cn/yNoDo

单链表头插:

void SLPushFront(SL** pphead, SLTDataType x)
{
	assert(pphead);
	SL* newnode = SLTBuyNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
		return;
	}
	newnode->next = *pphead;
	*pphead = newnode;
}

单链表头插输出:

单链表尾插:


void SLPopBack(SL** pphead)
{
	assert(pphead && *pphead);//判断pphead指针是否为空和节点是否为空
	//只有一个节点
	//因为->符号的优先级比*符号的优先级高所以不加括号就是pphead->next
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
		return;
	}
	//多个节点
	SL* Pfast = *pphead;
	SL* Pslow = NULL;
	//如果是用Pfast去判断的话那等while结束的时候到它会指向NULL,Plast会指向最后一个节点
    //最后我们是把NULL赋给Pfast->next以此来达到尾删的效果,那这样都不是删除最后一个节点而是给NULL赋NULL。
	//所以是要用Pfast->next去进行判断
	while (Pfast->next)
	{
		Pslow = Pfast;
		Pfast = Pfast->next;
	}
	Pslow->next = NULL;
	//最后别忘记销毁尾节点
	free(Pfast);
	Pfast = NULL;
}

单链表尾删输出:

单链表头删:

void SLPopFront(SL** pphead)
{
	assert(pphead && *pphead);
	//只有一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
		return;
	}
	//多个节点
	SL* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

单链表头删输出:

单链表查找:

SL* SLTFind(SL* phead, SLTDataType x)
{
	assert(phead);
	SL* Pcur = phead;
	while (Pcur)
	{
		if (Pcur->data == x)
		{
			return Pcur;
		}
		Pcur = Pcur->next;
	}
	return NULL;
}

查找输出:

在指定位置之前插入数据:
void SLTInsert(SL** pphead, SL* pos, SLTDataType x)
{
	assert(pphead && *pphead);
	assert(pos);//判断pos指针是否为空
	SL* newnode = SLTBuyNode(x);//扩容一个新节点
	//假设pos为头节点
	if (pos == *pphead)
	{   //头插
		SLPushFront(pphead , x);
		return;//插入完新数据直接return
	}
	SL* Pur = *pphead;
	//不为头节点
	while (Pur)
	{
		if (Pur->next == pos)
		{
			Pur->next = newnode;
			newnode->next = pos;
		}
		Pur = Pur->next;
	}
	return;
}

指定位置之前输出:

在指定位置之后插入数据:

//尾插不需要pos之前的指针,所以pphead在这里不起作用
void SLTInsertAfter(SL* pos, SLTDataType x)
{
	assert(pos);
	SL* newnode = SLTBuyNode(x);
	SL* Ptur = pos->next;//防止找不到它的下一个节点
	pos->next = newnode;
	newnode->next = Ptur;
}

指定位置之后输出:

删除pos指针:
void SLTErase(SL** pphead, SL* pos)
{
	assert(pphead && *pphead);
	assert(pos);
	//pos刚好是头结点,执行头删
	if (*pphead == pos) 
	{
		//头删
		SLPopFront(pphead);
		return;
	}
	SL* Pur = *pphead;
	//不为头节点
	while (Pur->next != pos)
	{
		Pur = Pur->next;
	}
	Pur->next = pos->next;
	free(pos);
	pos = NULL;
	return;
	//为什么错误?上面为什么对?
	//因为上面就是他先把pos置为空但是那个循环不会结束等到Pur->NULL时
	//那这又与pos相等了,如果再去访问pos->next就会报错
	//访问空指针的next就会出问题但是访问有效指针的next且那个next为空这样并不会报错
	/*while (Pur)
	{
		if (Pur->next == pos)
		{
			Pur->next = pos->next;
			free(pos);
			pos = NULL;
		}
		Pur = Pur->next;
	}*/
}

删除pos指针输出:

删除pos之后节点
void SLTEraseAfter(SL* pos)
{
	assert(pos);
	SL* Pur = pos->next;//保存Pur节点等下需要销毁这个节点
	pos->next = pos->next->next;
	free(Pur);
	Pur = NULL;
}

删除pos之后节点输出:

                                     上述代码全部都是用不带头节点编写而成 

单链表的优缺点:

 优点:
             1.简单易懂
             2.插入和删除操作高效
             3.动态内存管理

缺点:
             1.无法随机访问
             2.插入操作会破坏原有顺序
             3.无法向后遍历

双链表的定义:

在计算机科学中,双链表(DLL)是一种由元素序列组成的链接数据结构,每个元素称为节点,每个节点都有两个指针:一个指向序列中的下一个节点,另一个指向前面的节点。每个节点还包含一个数据元素。

双链表代码实现:

双链表存储结构:
typedef int LTDataType;
typedef struct DList
{
	struct DList* next;//后继节点
	struct DList* prev;//前驱节点
	LTDataType data;//节点数据
}DL;
双链表所有接口:
//初始化、销毁、输出
void LTInit(DL** pphead);
void LTDesTroy(DL** pphead);
void LTPrint(DL* phead);

//尾插、头插
void LTPushBack(DL* phead, LTDataType x);
void LTPushFront(DL* phead, LTDataType x);

//头删、尾删
void LTPopBack(DL* phead);
void LTPopFront(DL* phead);

//查找
DL* LTFind(DL* phead, LTDataType x);

//在pos位置之后插入数据、删除pos位置的数据
void LTInsert(DL* pos, LTDataType x);
void LTErase(DL* pos);
双链表初始化:
void LTInit(DL** pphead)
{
	*pphead = (DL*)malloc(sizeof(DL));//为哨兵位开辟空间
	if (*pphead == NULL)
	{
		perror("malloc error");
		exit(-1);
	}
    //双链表节点的初始化是前驱和后继指针都是指向自身
	(*pphead)->next = (*pphead)->prev = *pphead;
	(*pphead)->data = 0;
}

双链表初始化输出:

双链表销毁:
void  LTDesTroy(DL** pphead)
{
	assert(pphead);
	assert(*pphead);
	DL* Pfast = (*pphead)->next->next;
	DL* Pslow = (*pphead)->next;
	while (Pslow != NULL)
	{
		free(Pslow);
		Pslow = NULL;
		Pslow = Pfast;
		Pfast = Pfast->next;
	}
	free(*pphead);
	*pphead = NULL;
}

双链表销毁输出:

扩展双链表空间:
DL* DLTBuyNode(LTDataType x)
{
	DL* NewNode = (DL*)malloc(sizeof(DL));//为新节点开辟空间
	DL* Ptmp = NewNode;
	if (Ptmp == NULL)
	{
		perror("malloc error");
		exit(-1);
	}
	Ptmp->data = x;
	Ptmp->next = Ptmp->prev = NewNode;
	return NewNode;
}
双链表输出:
void LTPrint(DL* phead)
{
	assert(phead);
	DL* Pur = phead->next;//因为哨兵位没有数据所以不需要遍历它
	while (Pur != phead)
	{
		printf("%d->", Pur->data);
		Pur = Pur->next;
	}
	printf("\n");
}
双链表尾插:
void LTPushBack(DL* phead, LTDataType x)
{
    assert(phead);//判断phead指针是否为空
	DL* Newnode = DLTBuyNode(x);
	//先改变新节点
	Newnode->next = phead;//让新节点的后继指针指向头节点(原先是尾节点指向哨兵位的前驱)
	Newnode->prev = phead->prev;//让新节点的前驱指针指向尾节点

	//再改变尾节点
	phead->prev->next = Newnode;//让尾节点的后继指针指向新节点
	phead->prev = Newnode;//哨兵位的前驱指针指向新节点
}

双链表尾插输出:

双链表头插:
//双链表的头插并不是在哨兵位之前插入数据而是第一个有效节点之前插入
//在哨兵位之前插入数据就相当尾插,因为哨兵位前面就是最后一个有效节点
void LTPushFront(DL* phead, LTDataType x)
{
	assert(phead);
	DL* Newnode = DLTBuyNode(x);
	//先改变新节点的指向
	Newnode->next = phead->next;
	Newnode->prev = phead;

	phead->next->prev = Newnode;
	phead->next = Newnode;
}

双链表头插输出:

双链表尾删:
void LTPopBack(DL* phead)
{
	assert(phead);
	assert(phead->next != phead);//哨兵位指向自己就相当于双链表为空
	DL* pre = phead->prev;
	//先让尾节点的前一个节点的next指向哨兵位再让哨兵位的前驱指针指向尾节点的前一个节点那这样下 
    //来尾节点就相当于被销毁了
	phead->prev->prev->next = phead;//phead->prev就相当于尾节点然后phead->prev->prev就相当 
                                    //于尾节点的前一个节点
	phead->prev = phead->prev->prev;
	free(pre);
	pre = NULL;
	
}

双链表尾删输出:

双链表头删:
void LTPopFront(DL* phead)
{
	assert(phead);
	assert(phead->next != phead);
	DL* next = phead->next;//如果不先保存原哨兵位的next地址那删除完节点后再去 
                           //free(phead>next)这样就是删除新头节点了并不是再删除旧的头节点
	phead->next->next->prev = phead;
	phead->next = phead->next->next;
	free(next);
	next = NULL;
}

双链表头删输出:

双链表查找:
DL* LTFind(DL* phead, LTDataType x)
{
	assert(phead);
	DL* Pur = phead->next;//区别于与单链表的是这里传的并不是头节点而是头节点next
	while (Pur != phead)
	{
		if (Pur->data == x)
		{
			return Pur;
		}
		Pur = Pur->next;
	}
	return NULL;
}

双链表查找输出:

在指定位置之后插入数据:
void LTInsert(DL* pos, LTDataType x)
{
	assert(pos);
	DL* Newnode = DLTBuyNode(x);
	//依然是先修改新节点的指向
	Newnode->next = pos->next;
	Newnode->prev = pos;

	//不能先改变pos->next的指向因为修改了就找不到pos后面的节点
	//所以指向先改变pos后面节点的指向然后再改变pos的指向
	pos->next->prev = Newnode;
	pos->next = Newnode;
	
}

在指定位置之后插入数据输出:

删除pos位置的数据:
void LTErase(DL* pos)
{
	assert(pos);
	//先改变pos前面的节点那就找不到pos后面的节点,所以只能先改变后面再改变前面
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
}

删除pos位置的数据输出:

链表与顺序表的比较:

1.结构:

链表: 链表由一系列节点组成,每个节点包含数据元素和指向下一个节点的指针。节点之间的连接是通过指针实现的,因此链表是一种非连续的存储结构

顺序表顺序表将元素存储在连续的内存空间中,每个元素占用一个固定大小的单元。元素之间的访问通过索引实现,因此顺序表是一种连续的存储结构

2.逻辑结构与物理结构:

采用顺序存储时,逻辑上相邻的元素,对应的物理存储位置也相邻。而采用链式存储时,逻辑上相邻的元素,物理存储位置不一定相邻,对应的逻辑关系时通过指针链接来表示的。

3.遍历、插入、删除操作:

插入:在链表中插入新元素,需要修改相邻节点的指针以保持链表的顺序。在顺序表中插入新元素,如果空间不足则需要重新分配内存或移动现有元素。

删除:在链表中删除元素,需要修改相邻节点的指针以跳过被删除的元素。在顺序表中删除元素,需要将被删除元素后面的元素向前移动一个位置。

遍历在链表中遍历元素,需要逐个遍历节点并访问数据元素。在顺序表中遍历元素,可以使用循环访问每个元素

4.应用:

链表: 适用于需要频繁插入和删除操作的情景,因为链表的插入和删除操作效率较高,且不需要预先分配固定数量的内存空间。例如,缓存实现、栈和队列的底层实现等。

顺序表: 适用于需要随机访问数据的情景,因为顺序表的随机访问效率较高,可以直接通过索引访问任意位置的元素。例如,数组的底层实现、符号表等。

总结:

在选择数据结构时,需要根据具体应用场景权衡利弊。如果需要频繁插入和删除操作,并且对随机访问性能要求不高,则链表是一个不错的选择。如果需要随机访问数据,并且插入和删除操作不频繁,则顺序表是一个更好的选择。

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

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

相关文章

【JAVA入门】Day03 - 数组

【JAVA入门】Day03 - 数组 文章目录 【JAVA入门】Day03 - 数组一、数组的概念二、数组的定义2.1 数组的静态初始化2.2 数组的地址值2.3 数组元素的访问2.4 数组遍历2.5 数组的动态初始化2.6 数组的常见操作2.7 数组的内存分配2.7.1 Java内存分配2.7.2 数组的内存图 一、数组的概…

SAPUI5基础知识1 - 概览,库,支持工具,自学教程

1. SAPUI5 概览 1.1 SAPUI5 SAPUI5是一种用于构建企业级Web应用程序的开发框架。它是由SAP开发的&#xff0c;基于HTML5、CSS3和JavaScript技术。 SAPUI5提供了一套丰富的UI控件和工具&#xff0c;使开发人员能够快速构建现代化、可扩展和可定制的应用程序。 它还提供了数据…

cmake进阶:变量的作用域说明一(从函数作用域方面)

一. 简介 如同 C 语言一样&#xff0c;在 cmake 中&#xff0c;变量也有作用域的概念&#xff0c;本文我们就来聊一聊关于 cmake 中变量作用域的问题。 接下来从三个方面进行介绍&#xff1a;函数作用域、目录作用域以及全局作用域。 二. 函数作用域 我把这个作用域叫做函数…

文献速递:深度学习医学影像心脏疾病检测与诊断---利用深度学习进行动态心脏PET的自动帧间患者运动校正

Title 题目 Automatic Inter-frame Patient Motion Correction for Dynamic Cardiac PET Using Deep Learning 利用深度学习进行动态心脏PET的自动帧间患者运动校正 01 文献速递介绍 OSITRON正电子发射断层扫描&#xff08;PET&#xff09;心肌灌注成像已被证明相较于其他…

LeetCode-741. 摘樱桃【数组 动态规划 矩阵】

LeetCode-741. 摘樱桃【数组 动态规划 矩阵】 题目描述&#xff1a;解题思路一&#xff1a;动态规划&#xff0c;定推初遍举。解题思路二&#xff1a;倒序循环解题思路三&#xff1a;0 题目描述&#xff1a; 给你一个 n x n 的网格 grid &#xff0c;代表一块樱桃地&#xff0…

Android硬件加速hardwareAccelerated支持/不支持的绘图接口

Android硬件加速hardwareAccelerated支持/不支持的绘图接口 Android硬件加速也即在Androidmanifest.xml配置开启GPU渲染&#xff1a; <application android:hardwareAccelerated"true" > 配置后&#xff0c;Android将启用GPU渲染&#xff0c;在trace里面看会…

2023 年全国职业院校技能大赛(高职组)“云计算应用”赛项赛卷 B(容器云)

#需要资源&#xff08;软件包及镜像&#xff09;或有问题的&#xff0c;可私聊博主&#xff01;&#xff01;&#xff01; #需要资源&#xff08;软件包及镜像&#xff09;或有问题的&#xff0c;可私聊博主&#xff01;&#xff01;&#xff01; #需要资源&#xff08;软件包…

【一起深度学习——kaggle叶子分类】

kaggle 叶子分类 目的&#xff1a;将叶子进行分类。实现步骤&#xff1a;1、数据处理&#xff1a;2、加载数据3、 定义残差块4、定义Resnet模型。5、定义训练以及评估函数&#xff1a;6、开始训练&#xff1a;7、输出结果&#xff1a; 目的&#xff1a;将叶子进行分类。 实现步…

观测与预测差值自动变化系统噪声Q的自适应UKF(AUKF_Q)MATLAB编写

简述 基于三维模型的UKF&#xff0c;设计一段时间的输入状态误差较大&#xff0c;此时通过对比预测的状态值与观测值的残差&#xff0c;在相应的情况下自适应扩大系统方差Q&#xff0c;构成自适应无迹卡尔曼滤波&#xff08;AUKF&#xff09;&#xff0c;与传统的UKF相比&…

【Qt】按钮类控件

文章目录 1 :peach:Push Button:peach:2 :peach:Radio Buttion:peach:3 :peach:Check Box:peach:4 :peach:Tool Button:peach: 1 &#x1f351;Push Button&#x1f351; 使⽤ QPushButton 表⽰⼀个按钮&#xff0c;这也是当前我们最熟悉的⼀个控件了&#xff0c;QPushButton …

Ubuntu添加非root用户到Docker用户组

前言 首先平常公司的Linux生产环境为了防止误操作导致灾难性问题&#xff0c;一般都不会给我们开发开放root管理员的账号权限。所以平常在Ubuntu的普通用户登录的时候&#xff0c;要操作Dcoker一般都需要带上sudo来提升命令执行权限。为了解决这一问题&#xff0c;我们只需要将…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-13-按键实验

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

Axure中继器介绍以及案例分享

中继器是 Axure 中一个比较高阶的应用&#xff0c;它可以让我们在纯静态网页中模拟出类似带有后台数据交互的增删改查的效果。 一、中继器的基本使用方法&#xff1a; 整体流程分为三个步骤 ☆创建中继器 我们先在 Axured画布中拖入一个中继器元件 双击中继器后的效果 打开之…

java高并发实战<1>

我们一个请求--->tomcat--->db 我们只需要把我们的应用部署在tomcat中&#xff0c; 就可以了 这就是你单体的感念&#xff0c;单机结构你只用一个服务器就完成了你项目的部署单点问题一旦这台机器挂了,用户就没有办法用你这个服务,单机能力有限 随着你用户量增长的过程…

04.添加自定义监控项

添加自定义监控项 监控项就是监控每一个指标 1.命令行&#xff0c;手动取值 [rootyunlong66 ~]# iostat |awk $1 ~/sda/ sda 5.89 36.10 122.71 557910 1896585 [rootyunlong66 ~]# iostat |awk $1 ~/sda/{print $2} 5.892.修改zabbix-age…

OpenNJet下载安装及入门实战教程

一、什么是OpenNJet OpenNJet是一款开放原子开源基金会孵化及运营的开源项目。OpenNJet采用C语言实现。是一款高性能、轻量级的WEB应用及代理软件。    OpenNJet 应用引擎是高性能、轻量级的WEB应用与代理软件。作为云原生服务网格的数据平面&#xff0c;NJet具备动态配置加载…

【Git】回滚旧提交版本且不影响最新提交版本

【Git】回滚旧提交版本且不影响最新提交版本 一、场景假设 远程仓库origin中有一个分支main&#xff0c;有4次提交记录&#xff1a;v1、v2、v3、v4。 二、需求 需要回滚旧提交版本&#xff0c;但不影响已有的所有提交版本&#xff08;即不影响最新提交版本&#xff09;&…

k8s保持pod健康

存活探针 Kubemetes 可以通过存活探针 (liveness probe) 检查容器是否还在运行。可以为 pod 中的每个容器单独指定存活探针。如果探测失败&#xff0c;Kubemetes 将定期执行探针并重新启动容器。 Kubemetes 有以下三种探测容器的机制&#xff1a; HTTP GET 探针对容器的 IP 地…

深入探索归并排序算法:分而治之的排序艺术

在计算机科学领域&#xff0c;排序算法是一项基础且重要的技术&#xff0c;归并排序作为一种经典的分治算法&#xff0c;以其稳定性和高效性而闻名。本文将带您深入探索归并排序算法的原理、实现方法以及应用场景&#xff0c;揭示这一排序艺术背后的精髓。 **归并排序算法简介…

【管理篇】管理三步曲:管理规划(一)

目录标题 管理到底都要做哪些事呢如何开始带团队&#xff1f; 职能&#xff1a;如何界定团队是干什么的&#xff1f;目标&#xff1a;如何为团队设定合理的目标规划资源&#xff1a;需要申请哪些资源&#xff08;1&#xff09;你是否了解资源的丰富性&#xff1f;&#xff08;2…