【数据结构】数据结构中的隐藏玩法——栈与队列

前言:

哈喽大家好,我是野生的编程萌新,首先感谢大家的观看。数据结构的学习者大多有这样的想法:数据结构很重要,一定要学好,但数据结构比较抽象,有些算法理解起来很困难,学的很累。我想让大家知道的是:数据结构非常有趣,很多算法是智慧的结晶,我希望大家在学习数据结构的过程是一种愉悦的心情感受。因此我开创了《数据结构》专栏,在这里我将把数据结构内容以有趣易懂的方式展现给大家。

1.栈

1.1栈的定义

怎么给大家引入队列概念呢?有了,我们在中学学习化学时肯定接触过下面这个实验器材:

胶头滴管是我们在学习化学常使用的一种实验器材,胶头滴管用于精确地滴取液体。它通常由一个透明的玻璃或塑料瓶身和一个连接瓶身和滴液管的胶头组成。 我们使用时一般是将胶头浸入所需液体中,轻轻按压胶头,使其充满液体,将胶头滴管垂直放置到需要滴液的容器中,轻轻松开手指,让液体滴下。后进入胶头滴管的液体将会先滴出,先进入的胶头滴管的液体反而后滴出,像这样的例子反而可以引入数据结构——栈。

在我们软件应用中,栈这种后进先出的数据结构的应用是非常普遍的。比如我们用浏览器上网时不管什么浏览器都有一个“后退键”,当我们点击后可以按访问顺序逆序加载浏览过的网站。比如你正在浏览一篇介绍C语言相关内容的博客,你在看博主分享的代码,突然发现一个函数博主没详细介绍,你也不了解这个函数的功能,打开了CPlusPlus网站搜索它的功能,找到之后你又想返回去接着阅读,这时候单击左上角的“后退键”。如下图:

很多软件都有撤销操作,这也是使用栈来实现的,当然不同的软件具体实现代码会有很大差异,不过原理都是一样的。 栈是限定仅在表尾进行插入和删除操作的线性表。我们把允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈,栈又称为先进后出(Last In First Out)的线性表,简称LIFO结构。首先我们要知道栈是一个线性表,也就是说,栈元素具有线性关系,即前驱后驱关系,只不过它是一种特殊的线性表,前面定义中提到了在线性表的表尾进行插入和删除操作,这里的表尾指得是栈顶,而不是栈底。它的特殊之处就在于限制了这个线性表的插入和删除位置,他始终只在栈顶进行,这也就使得:栈底是固定的,最先进入栈的只能在栈底。栈的插入操作,叫做进栈,也叫压栈、入栈。

栈的删除操作,叫做出栈,有的也叫弹线。 

1.2进栈出栈的变化形式

这个最先进栈的元素,是不是只能是最后出栈呢?答案是不一定的,要看什么情况。栈对线性表的插入和删除的位置进行了限制,并未对元素出栈的时间进行限制,也就是说,在不是所有的元素都进栈的情况下,事先进入栈的元素也可以出栈,只要保证是栈顶元素就行,举例来说,如果我们现在是3个整型数字1、2、3依次进栈,会有哪些出栈的次序呢?

  1. 第一种:1、2、3进,再3、2、1出,这是最简单最好理解的一种,出栈次序为3、2、1。
  2. 第二种:1进,1出,2进,2出,3进,3出,也就是一个一个出嘛,出栈次序为1、2、3。
  3. 第三种:1进,2进,2出,1出,3进,3出。出栈次序为2、1、3。
  4. 第四种:1进,1出,2进,3进,3出,2出。出栈顺序为1、3、2。
  5. 第五种:1进,2进,2出,3进,3出,1出。出栈顺序为2、3、1。

有没有可能是3、1、2这样的次序呢?肯定是不会的,因为3先出栈的话,就意味着3曾经进过栈,既然3都进栈了,那么1和2也早就进栈了,此时2一定是在1的上面,更接近栈顶,那么出栈只可能是3、2、1,不然不满足1、2、3依次进栈的要求,所以不会出现1会比2先出栈的情况。下面给大家举两个简单的练习:

1.一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出栈的顺序是( )。

A.12345ABCDE

B.EDCBA54321

C.ABCDE12345

D.54321EDCBA

答案:B

2.若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()

A.1432

B.2341

C.3142

D.3421

答案:C

1.3栈的各个功能的实现

上面我们也提到了栈是一个特殊的线性表,所以线性表的顺序存储和链式存储对于栈来说,也同样适用。所以栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些:

  1. 存储效率高:数组使用连续的内存空间存储数据,在访问元素时,可以直接通过索引访问,不需要额外的指针,因此访问速度更快。而链表每个节点需要存储数据和指向下一个节点的指针,占用更多的内存空间。
  2. 空间效率高:数组的存储空间是预先分配的连续内存块,不需要额外的指针来表示节点之间的链接关系,因此相对于链表来说,占用的内存空间更小。
  3. 实现简单:使用数组实现栈,只需要一个指针来表示栈顶的位置,通过调整指针的位置即可进行进栈和出栈操作。而链表实现栈需要额外的指针来表示栈顶和节点之间的链接关系,实现起来更加复杂。
  4. 随机访问:由于数组支持随机访问,可以直接通过索引访问栈中的任意元素。而链表只支持顺序访问,需要从头节点开始依次遍历到目标节点。
  5. 空间预分配:数组在创建时需要指定大小,可以根据需求进行空间的预分配。而链表可以根据实际情况动态调整大小,但可能会导致频繁的内存分配和释放操作。

所以在这里我们就是用数组来实现栈。我们先来定义一下栈的结构:

typedef int STDatatype;
typedef struct stack
{
	STDatatype* a;
	int top;      //栈顶
	int capacity;//容量
}ST;

1.3.1栈的初始化和销毁

通过上面栈的结构的定义,可以看出来它和我们之前写的顺序表极其相似,栈的初始化和顺序表基本相同:函数接受一个指向栈对象的指针pst,并使用assert断言函数确保pst不为 NULL,以确保安全性。接下来,将栈对象pst的成员变量a设置为 NULL。这表示栈中的元素存储数组当前为空,因为还没有分配内存。将栈对象pst的成员变量capacity设置为 0,这表示栈的当前容量为0,还没有分配内存。那么top初始化也为0吗?很多的数据结构相关书籍在介绍栈的初始化的时候都将top初始化为-1,这是因为栈为空栈的时候top等于0,当栈中有一个元素的时候top也为0,因此通常把空栈的判定条件定位top等于-1。当然将top初始化为0也是可以的,top的意义会发生变化,这时候我们让top指向的时栈顶的下一个元素。大多数书上都是以-1来初始化,那我就用0来初始化。我们来实现一下栈的初始化函数:

void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->capacity = 0;
	pst->top = 0;
}

 栈的销毁是将栈占用的内存空间释放掉,栈的销毁具体操作步骤为:

  1. 将栈对象的成员变量a设置为 NULL,表示栈中的元素存储数组为空。
  2. 将栈对象的成员变量capacity设置为 0,表示栈的容量为0。
  3. 将栈对象的成员变量top设置为 0,表示栈为空。

我们来实现一下栈的销毁:

void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = pst->capacity = 0;
}

1.3.2栈中的入栈和出栈操作

栈的入栈具体操作步骤为:

  1. 检查栈是否已满。如果栈已满,那么无法将新元素入栈。这种情况下,可能需要扩展栈的容量或者处理溢出的方式。
  2. 如果栈未满,则将新元素放置在栈顶位置。
  3. 前面我们说了给top定义为0(即栈顶的下一个元素),所在这里我们还要将top+1。

我们来实现一下入栈的操作:

void STPush(ST* pst, STDatatype x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		ST* tmp = (ST*)realloc(pst->a, sizeof(ST));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return -1;
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}

栈的出栈具体操作步骤为:

  1. 检查栈是否为空。如果栈为空,无法执行出栈操作,因为栈中没有元素可以出栈,这时候我们可以使用assert断言一下。
  2. 如果栈非空,则将栈顶元素移除。在数组实现栈中,可以通过将栈顶指针减1,来实现将栈顶元素出栈。

我们来具体实现一下出栈的操作:

void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}

1.3.3栈中的其他操作

 我们在栈中能进行的操作不仅仅只有入栈和出栈两种操作,在这里再和大家介绍一些其他的操作。首先先来介绍获取栈顶元素操作,其具体操作步骤为:

  1. 检查栈是否为空。如果栈为空,无法获取栈顶元素,因为栈中没有元素可用。这时候我们仍然可以用assert来断言一下。

  2. 如果栈非空,则返回栈顶元素的值。注意不要返回top所在位置,因为我们给它的定义是栈顶的下一个元素。

我们来实现一下获取栈顶元素的函数:

STDatatype STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	return pst->a[pst->top - 1];
}

获取栈中元素的个数实现就简单了,直接返回top的值即可,我们来实现一下这个函数:

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

 判断栈是否为空我们只需要判断top是否为0即可,我们来实现一下 :

int STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}

1.4多文件实现栈

stack.h文件:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDatatype;
typedef struct stack
{
	STDatatype* a;
	int top;      //栈顶
	int capacity;//容量
}ST;
void STInit(ST* pst);//栈的初始化
void STPush(ST* pst, STDatatype x);//栈的插入
void STPop(ST* pst);//栈的删除
STDatatype STTop(ST* pst);//获取栈顶元素
int STSize(ST* pst);//获取栈中有效的元素个数
int STEmpty(ST* pst);//检测栈是否为空
void STDestroy(ST* pst);//栈的销毁

 stack.c文件:

#include"stack.h"
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->capacity = 0;
	pst->top = 0;
}
void STPush(ST* pst, STDatatype x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		ST* tmp = (ST*)realloc(pst->a, sizeof(ST));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return -1;
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}
void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}
STDatatype STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	return pst->a[pst->top - 1];
}
int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}
int STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}
void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = pst->capacity = 0;
}

test.c文件(用来测试函数功能):

#include"stack.h"
void Test1()
{
	ST s;
	STInit(&s);
	STPush(&s, 1);
	STPush(&s, 2);
	STPush(&s, 3);
	STPush(&s, 4);
	printf("%d ", STTop(&s));
	STPop(&s);
	printf("%d\n", STTop(&s));
	STPop(&s);
	STPush(&s, 4);
	STPush(&s, 5);
	while (!STEmpty(&s))
	{
		printf("%d ", STTop(&s));
		STPop(&s);
	}
	printf("\n");
}
int main()
{
	Test1();
	return 0;
}

 

2.队列 

2.1队列的定义

 大家在使用电脑的时候都应该经历过这种情况:电脑有时候疑似死机状态,鼠标点击什么都好像没有效果,无论怎么点击文件都没动静,就当我们失去耐心的时候,想要将它重启的时候,它好像清醒过来一样,把你刚才的操作全部按顺序执行了一遍——疯狂弹窗。这是因为操作系统在当时CPU一时忙不过来,等前面的事情忙完之后,后面多个指令需要通过一个通道输出,按先后次序排队执行造成的结果。再比如我们在某个网红店铺进行网购时,我们想要询问客服时,客服人员相对于顾客是较少的,在所有客服都占线的情况下,客户会被要求等待,直到某个客服空下来,才能让和先等待的客户联系,这里也是因为对当前所有联系客服的客户进行了排队处理。

上面的例子中都是应用了一种数据结构来实现刚才提到的先进先出的排队功能,这就是队列队列是只允许一端进行插入的操作,而在另一端进行删除操作的线性表。队列是一种先进先出(First In First Out)的线性表,简称FIFO,允许插入的一端称为队尾,允许删除的一端称为队头。下图中1就是这个队列的队头,4是这个队列的队尾。这样我们就可以删除时总是从队头开始,而插入时从队尾插入。这也符合我们的一个习惯:排在第一个优先出队列,最后来的排队尾。

2.2 队列的各个功能的实现

队列和栈一样也是一种特殊的线性表,它一般也可以使用数组或者链表来实现,队列和栈不一样,它使用链表实现更优一些:

  1. 动态扩容:链表实现的队列可以动态地增加或减少节点,不需要预先定义容量。当需要插入新的元素时,可以直接创建新的节点并将其插入到队列的尾部,而不需要考虑数组的容量限制。这样可以更灵活地适应不同规模的数据。
  2. 内存利用率高:链表实现的队列只会使用实际需要的内存,不会浪费额外的内存。相比之下,数组实现的队列必须预先分配一定大小的连续内存空间,如果队列的实际大小远小于数组的容量,就会造成内存浪费。
  3. 插入和删除操作高效:链表实现的队列在插入和删除操作上具有较高的效率。在链表中插入或删除一个节点的时间复杂度是 O(1),而在数组中插入或删除一个元素则需要移动其他元素,其时间复杂度是 O(n)。当队列的规模很大时,链表实现的队列会更加高效。
  4. 队列长度无限制:链表实现的队列的长度理论上没有限制,只受限于计算机内存的大小。相比之下,使用数组实现的队列必须预先定义一个固定的容量,当元素数量超过容量时,需要进行扩容操作。
  5. 更容易实现其他特殊操作:链表实现的队列更容易实现一些特殊操作,例如反转队列、合并队列等。这是因为链表的灵活性和可动态调整的特性,使得实现这些操作更为简单。

 在这里我们使用链表来实现队列,我们先来定义一下队列的结构:

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;
typedef struct Queue
{
	QNode* phead;
	QNode* tail;
	int size;
}Queue;

在上面的定义中,我们首先定义了一个结构体QueueNode,用该结构体表示队列中的节点,它包含两个成员变量:

  1. data:存放在节点中的数据。
  2. next:指向下一个节点的指针。

 然后又定义了一个结构体Queue来表示队列本身,它包含三个成员变量:

  1. phead:指向队列头部的指针。该指针指向队列中的第一个节点。
  2. tail:指向队列尾部的指针。该指针指向队列中的最后一个节点。
  3. size:表示队列的大小,即队列中节点的数量。

2.2.1队列的初始化和销毁

 我们初始化时只需要将队列的成员变量初始化为合适的初值就可以了,我们来实现一下队列的初始化:

void QueueInit(Queue* q)
{
	assert(q);
	q->phead = q->tail = NULL;
	q->size = 0;
}

 队列销毁的操作具体步骤为:

  1. 遍历队列元素:从队列的头指针开始,依次遍历队列中的每个节点。

  2. 释放节点内存:通过free函数释放每个节点的内存空间。确保释放节点时,先保存下一个节点的指针,然后释放当前节点的内存。

  3. 然后将队列的头指针和尾指针置空,给size赋值为0,表示是一个空的队列。

我们来实现一下队列的销毁:

void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->phead = q->tail = NULL;
	q->size = 0;
}

2.2.2队列的入队和出队操作

使用上面的定义方法使我们在队列的操作更加方便快捷:

  1. 入队操作可以将新元素添加到队列的尾部,只需将新节点插入到tail指针所指的节点后面,并更新tail指针为新节点。
  2. 出队操作可以从队列的头部删除一个元素,只需将phead指针指向下一个节点,并释放原来头部节点的内存空间。
  3. 获取队列大小只需直接访问size变量的值。

 我们先来实现一下队列的入队操作:

void QueuePush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return -1;
	}
	newnode->data = x;
	newnode->next = NULL;
	if (q->tail == NULL)
	{
		q->phead = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;
}

我们来实现一下队列的出队操作:

void QueuePop(Queue* q)
{
	assert(q);
	assert(q->phead);
	QNode* cur = q->phead;
	q->phead = q->phead->next;
	free(cur);
	cur = NULL;
	if (q->phead == NULL)
		q->tail = NULL;
	q->size--;
}

既然在上面提到了获取队列的大小,那我们就来实现一下:

int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}

2.2.3获取队列的队头和队尾元素

获取队列的队头元素的具体操作步骤为:

  1. 检查队列是否为空:判断队列的头指针是否为空,如果为空则表示队列为空,无法获取队头元素。
  2. 返回队头元素的值:如果队列不为空,直接返回队列的头指针所指向的节点的值。

我们来实现一下获取队头元素的操作:

QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->phead);
	return q->phead->data;
}

获取队尾元素操作的具体步骤为:

  1. 检查队列是否为空,如果队列为空,则无法获取队尾元素。
  2. 返回队尾元素的值:如果队列不为空,直接返回队列尾指针所指向节点的值。

我们来实现一下获取队尾元素的操作:

QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->tail);
	return q->tail->data;
}

2.3多文件实现队列

Queue.h文件:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int QDataType;
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;
typedef struct Queue
{
	QNode* phead;
	QNode* tail;
	int size;
}Queue;
void QueueInit(Queue* q);//队列的初始化
void QueuePush(Queue* q, QDataType x);//队尾入队列
void QueuePop(Queue* q);//对头出队列
QDataType QueueFront(Queue* q);//获取队头元素
QDataType QueueBack(Queue* q);//获取队尾元素
int QueueSize(Queue* q);//获取队列中的元素个数
int QueueEmpty(Queue* q);//检测队列是否为空
void QueueDestroy(Queue* q);//队列的销毁

Queue.c文件:

#include"Queue.h"
void QueueInit(Queue* q)
{
	assert(q);
	q->phead = q->tail = NULL;
	q->size = 0;
}
void QueuePush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return -1;
	}
	newnode->data = x;
	newnode->next = NULL;
	if (q->tail == NULL)
	{
		q->phead = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;
}
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->phead);
	QNode* cur = q->phead;
	q->phead = q->phead->next;
	free(cur);
	cur = NULL;
	if (q->phead == NULL)
		q->tail = NULL;
	q->size--;
}
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->phead);
	return q->phead->data;
}
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->tail);
	return q->tail->data;
}
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->phead == NULL;
}
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->phead = q->tail = NULL;
	q->size = 0;
}

test.c文件(用来测试函数功能):

#include"Queue.h"
void Test1()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	printf("%d ", QueueFront(&q));
	QueuePop(&q);
	printf("%d ", QueueFront(&q));
	QueuePop(&q);
	printf("\n");
	QueuePush(&q, 4);
	QueuePush(&q, 5);
	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	printf("\n");
	QueueDestroy(&q);

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

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

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

相关文章

UE5 像素流web 交互2

进来点个关注不迷路谢谢&#xff01; ue 像素流交互多参数匹配 主要运用像素流的解析json 状态&#xff1a; 测试结果&#xff1a; 浏览器控制台&#xff1a; 接下来编写事件传递 关注下吧&#xff01;

webshell工具-冰蝎流量特征和加密方式

一、冰蝎原理 1.1 简介 冰蝎是一款基于Java开发的动态加密通信流量的新型Webshell客户端&#xff0c;由于通信流量被加密&#xff0c;传统的WAF、IDS 设备难以检测&#xff0c;给威胁狩猎带来较大挑战。冰蝎其最大特点就是对交互流量进行对称加密&#xff0c;且加密密钥是由随…

【颜色】windows自带画图中的颜色编辑

结论&#xff1a;颜色编辑中的色调、饱和度和亮度&#xff0c;是与HSL颜色空间保持一致。 如下图所示&#xff0c;他有色调、饱和度和亮度&#xff0c;其数值范围均为[0,240]。 首先我使用HSV进行模拟&#xff0c;发现效果和数值对不上。 因此改换HSL进行模拟&#xff0c;其数…

NodeJS安装并生成Vue脚手架(保姆级)

文章目录 NodeJS下载配置环境变量Vue脚手架生成Vue脚手架创建项目Vue项目绑定git 更多相关内容可查看 NodeJS下载 下载地址&#xff1a;https://nodejs.org/en 下载的速度应该很快&#xff0c;下载完可以无脑安装&#xff0c;以下记得勾选即可 注意要记住自己的安装路径&…

每日AIGC最新进展(10):符号音乐生成SYMPLEX、新型图像编辑数据集ReasonPix2Pix、角色一致性插画生成、高级的风格个性化扩散模型

Diffusion Models专栏文章汇总&#xff1a;入门与实战 SYMPLEX: Controllable Symbolic Music Generation using Simplex Diffusion with Vocabulary Priors http://arxiv.org/abs/2405.12666v1 本文介绍了一种新的符号音乐生成方法&#xff0c;名为SYMPLEX&#xff0c;它基于…

台湾省军事演习路径规划:A*算法在复杂地形中的应用

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容&#xff0c;和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣&#xff01; 推荐&#xff1a;数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航&#xff1a; LeetCode解锁100…

在MySQL中,Linux表同步到Windows,有大小写的就没同步的详细解决方案

在 Linux 系统上&#xff0c;文件名是区分大小写的&#xff0c;而在 Windows 系统上&#xff0c;文件名通常不区分大小写。导致在从 Linux 同步文件到 Windows 时&#xff0c;有些文件因为名称冲突而无法同步。为了有效解决这个问题&#xff0c;可以采取以下方法&#xff1a; …

1098: 堆的判断

解法&#xff1a; 堆是完全二叉树 用数组来存储 然后用定义判定 #include<iostream> #include<vector> using namespace std; int main() {int n;cin >> n;vector<int> vec(n);for (int i 0; i < n; i) cin >> vec[i];for (int i 0; i &…

【Linux】关于获取进程退出状态中的core dump标志补充

通过 wait/waitpid 可以获取子进程的退出状态, 从而判断其退出结果. 记录退出状态的 int 变量 status 的使用情况如下图所示: 如果是收到信号终止的话, 低 7 位为收到的终止信号, 而低第 8 位为 core dump 标志, core dump 标志有什么用呢? core dump 标志只存 0/1, 表示是否…

c#自动生成缺陷图像-添加新功能(可从xml直接提取目标数据,然后进行数据离线增强)--20240524

在进行深度学习时,数据集十分重要,尤其是负样本数据。 故设计该软件进行深度学习数据预处理,最大可能性获取较多的模拟工业现场负样本数据集。 该软件基于VS2015、.NETFrameWork4.7.2、OpenCvSharp1.0.0.0、netstandard2.0.0.0、SunnyUI3.2.9.0、SunnyUI.Common3.2.9.0及Ope…

ClickHouse实战处理(一):MergeTree表引擎

MergeTree作为家族系列最基础的表引擎&#xff0c;主要有以下特点&#xff1a; 存储的数据按照主键排序&#xff1a;创建稀疏索引加快数据查询速度。支持数据分区&#xff0c;可以通过PARTITION BY语句指定分区字段。支持数据副本。支持数据采样。 一、MergeTree分类和建表参…

python水果分类字典构建指南

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、理解需求 三、构建字典 1. 数据结构选择 2. 代码实现 3. 结果展示 四、总…

C++实现基础二叉搜索树(并不是AVL和红黑树)

本次实现的二叉搜索树并不是AVL数和红黑树&#xff0c;只是了解流程和细节。 目录 二叉搜索树的概念K模型二叉搜索树的实现二叉搜索树的架构insert插入find 查找中序遍历Inorder删除earse替换法的思路情况一 &#xff1a;假如要删除节点左边是空的。在左边时在右边时 情况二&a…

JavaScript-数组的增删改查

数组的操作一共有四种&#xff1a; 查询数组数据修改数组中元素的值数组添加新的数据删除数组中的元素 数组的初始化 有些编程语言的数组初始化是用{}包着的&#xff0c;而JS的数组初始化用[] let num[2,6,1,77,52,25,7]; 数组的查询 想要具体查询数组中的某个元素 可以用数…

【Spring Cloud】全面解析服务容错中间件 Sentinel 持久化两种模式

文章目录 推送模式本地文件持久化&#xff08;拉模式&#xff09;配置yml编写处理类添加配置演示 配置中心持久化&#xff08;推模式&#xff09;修改nacos在sentinel中生效引入依赖配置文件 修改sentinel在nacos中生效下载源码更改代码演示 总结 推送模式 Sentinel 规则的推送…

【JavaEE 初阶(十)】JVM

❣博主主页: 33的博客❣ ▶️文章专栏分类:JavaEE◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多进阶知识 目录 1.前言2.JVM内存区域划分3.类加载3.1双亲委派模型 4.垃圾回收&#xff08;GC&#xff0…

结构体变量的创建和初始化以及内存对齐

前言 嗨&#xff0c;我是firdawn&#xff0c;在本章中我们将介绍&#xff0c;结构体变量的创建和初始化&#xff0c;结构成员访问操作符以及结构体的内存对齐&#xff0c;下面是本章的思维导图&#xff0c;接下来&#xff0c;让我们开始今天的学习吧&#xff01; 一&#xf…

下载CentOS系统或者下载Ubuntu系统去哪下?

因为Centos官网是挂在国外的服务器上&#xff0c;下载镜像时相比于国内的下载速度会慢很多&#xff0c;分享国内的镜像站去阿里巴巴下载Centos镜像。 首先分享两种下载方式&#xff0c;如果只想下载Centos那么就访问方式一的下载地址即可&#xff0c;如果还想下载其他的系统&a…

AI大模型探索之路-实战篇5: Open Interpreter开放代码解释器调研实践

系列篇章&#x1f4a5; AI大模型探索之路-实战篇4&#xff1a;DB-GPT数据应用开发框架调研实践 目录 系列篇章&#x1f4a5;前言一、何为Open Interpreter&#xff1f;二、与 ChatGPT 的代码解释器比较三、 Open Interpreter的特性1、强大的本地计算能力2、丰富的功能3、高度的…

基于springboot+vue的招聘信息管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…