【数据结构与算法】走进数据结构的“时间胶囊”——栈

大家好,我是小卡皮巴拉

文章目录

目录

引言

一.栈的基本概念

1.1 定义

1.2 特性

1.3 基本操作

二.栈的实现方式

2.1 顺序栈

2.2 链栈

三.顺序栈的实现

定义顺序栈的结构

初始化

入栈

检查栈是否为空

出栈

销毁

四.链栈的实现

定义链栈的结构

初始化

 入栈

检查栈是否为空

出栈

销毁

兄弟们共勉!!!  


每篇前言

博客主页:小卡皮巴拉 

咱的口号:🌹小比特,大梦想🌹

作者请求:由于博主水平有限,难免会有错误和不准之处,我也非常渴望知道这些错误,恳请大佬们批评斧正。

引言

在数据结构的大家庭中,栈以其独特的“后进先出”特性脱颖而出,就像是一个记录时间流逝的“时间胶囊”。每当有新数据加入时,它就被放置在栈顶,而最早加入的数据则静静地躺在栈底,等待被最后一个取出。

栈不仅是一个简单的数据结构,更是算法设计和程序优化中的得力助手。从函数调用栈的管理到递归问题的求解,栈的身影无处不在。它以其简洁明了的数据操作规则和高效的内存利用方式,成为了程序员们解决复杂问题时的首选工具。

在接下来的篇章中,我们将一起探索栈的奥秘,从定义到特性,再到丰富的应用场景,帮助大家真正掌握这一数据结构的核心知识。

一.栈的基本概念

1.1 定义

栈(Stack)是一种只允许在一端进行插入或删除的线性表。这端被称为栈顶(Top),另一端则被称为栈底(Bottom)。栈遵循后进先出(Last In First Out,LIFO)的原则,即最后插入的元素会第一个被删除。

1.2 特性

  • 后进先出:栈中最后一个插入的元素首先被删除。这是栈最显著的特点,也是它与其他线性表(如数组、链表)的主要区别。

  • 栈顶浮动,栈底固定:栈顶的位置随着元素的入栈和出栈而变化,而栈底则保持不变。

  • 不支持随机访问:栈的结构决定了只能在栈顶进行插入和删除操作,无法直接访问和修改栈中间的元素。

1.3 基本操作

栈的基本操作主要包括以下几种:

  1. 初始化栈:创建一个空栈,并设置栈底指针和栈顶指针。

  2. 判断栈是否为空:检查栈中是否包含元素,若栈为空则返回true,否则返回false。

  3. 入栈操作(Push):将新元素添加到栈顶。若栈未满,则将新元素放入栈中,并更新栈顶指针。

  4. 出栈操作(Pop):从栈顶移除元素。若栈非空,则弹出栈顶元素,并更新栈顶指针。

  5. 读取栈顶元素(GetTop/Peek):返回栈顶元素的值,但不删除它。若栈非空,则返回栈顶元素的值。

  6. 销毁栈:释放栈占用的存储空间。

二.栈的实现方式

栈的实现方式主要有两种:

2.1 顺序栈

利用数组实现,附设一个指针(top)指示当前栈顶元素的位置。顺序栈需要预分配一块连续的存储空间,其优点是访问速度快,但缺点是存在栈满上溢的风险。

2.2 链栈

采用链表实现,通常使用单链表,并规定所有操作都在链表的表头进行。链栈的优点是便于多个栈共享存储空间、不存在栈满上溢的情况,且插入和删除操作的时间复杂度为O(1)。但缺点是需要额外的指针存储空间。

三.顺序栈的实现

定义顺序栈的结构

首先,我们定义了一个名为STDataType的类型别名,它基于int类型。这个类型别名将用于栈中存储的数据元素。

接着,我们定义了一个名为Stack的结构体(通过typedef,我们也可以用ST来引用它)。这个结构体代表了一个栈的数据结构,并包含以下三个成员:

  1. arr:这是一个指向STDataType类型的指针。它用于动态分配数组,以存储栈中的元素。

  2. top:这是一个整型变量,表示栈顶的位置。在栈中,我们通常将数组的最后一个有效元素的位置视为栈顶。注意,这里的top成员变量实际上存储的是栈顶元素的索引(即数组中的位置),而不是指向栈顶元素的指针。因此,栈为空时,top的值通常被初始化为-1或栈的容量减1(取决于栈的实现方式)。

  3. capacity:这是一个整型变量,表示栈的容量,即栈能够存储的最大元素数量。这个值在栈的初始化时被设定,并且决定了为arr成员动态分配多少内存。

函数代码:

typedef int STDataType;
//定义栈的数据结构
typedef struct Stack
{STDataType* arr;int top;//指向栈顶位置int capacity;
}ST;

初始化

STInit函数用于初始化一个栈。它接收一个指向栈的指针ps作为参数。

  1. 检查指针:首先,使用assert确保传入的栈指针ps不是NULL

  2. 设置初始状态

    • 将栈的数组指针ps->arr设置为NULL,表示栈尚未分配存储空间。
    • 将栈顶位置ps->top设置为0,表示栈为空。
    • 将栈容量ps->capacity也设置为0,表示栈当前没有预设容量。

这样,栈就被初始化为一个空栈,准备进行后续的栈操作。

函数代码:

//初始化
void STInit(ST* ps)
{assert(ps);ps->arr = NULL;ps->top = ps->capacity = 0;
}

入栈

StackPush函数用于将一个元素压入栈顶。它接收两个参数:一个指向栈的指针ps和要压入栈的元素x

  1. 检查指针:首先,使用assert确保传入的栈指针ps不是NULL

  2. 检查容量:接着,检查栈是否已满(即栈顶位置ps->top是否等于栈容量ps->capacity)。

    • 如果栈已满,则进行扩容操作。首先计算新的容量newCapacity,如果当前容量为0,则新容量为4(初始容量),否则新容量为当前容量的两倍。
    • 使用realloc函数尝试为栈的数组ps->arr分配新的内存空间。如果realloc失败(返回NULL),则打印错误信息并退出程序。
    • 如果realloc成功,则更新栈的数组指针ps->arr和栈容量ps->capacity
  3. 入栈操作:在确认栈有足够的空间后,将元素x放入栈顶位置(即ps->arr[ps->top]),并将栈顶位置ps->top加1,以指向下一个空位置。

这样,元素x就被成功压入栈顶,栈的栈顶位置和容量(如果需要的话)也得到了更新。

函数代码:

void StackPush(ST* ps, STDataType x)  
{  assert(ps); // 确保栈指针有效  // 检查栈是否已满  if (ps->top == ps->capacity)  {  // 扩容操作  int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;  STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));  if (tmp == NULL)  {  perror("realloc fail!\n");  exit(1); // 扩容失败,退出程序  }  ps->arr = tmp; // 更新栈的数组指针  ps->capacity = newCapacity; // 更新栈的容量  }  // 入栈操作  ps->arr[ps->top++] = x; // 将元素放入栈顶,并更新栈顶位置  
}

检查栈是否为空

StackEmpty函数用于判断一个栈是否为空。它接收一个指向栈的指针ps作为参数,并返回一个布尔值。

  1. 检查指针:首先,使用assert确保传入的栈指针ps不是NULL

  2. 判断栈是否为空:然后,通过比较栈顶位置ps->top是否等于0来判断栈是否为空。如果ps->top等于0,表示栈中没有元素,栈为空;否则,栈不为空。

  3. 返回结果:最后,根据判断结果返回相应的布尔值。如果栈为空,则返回true(或等价地,返回非零值,但在C语言中通常使用true1来表示真);如果栈不为空,则返回false(或等价地,返回零值)。

函数代码:

#include <stdbool.h> // 包含头文件以支持布尔值  bool StackEmpty(ST* ps)  
{  assert(ps); // 确保栈指针有效  return ps->top == 0; // 判断栈是否为空,并返回结果  
}

出栈

StackPop函数用于从栈中移除栈顶元素。它接收一个指向栈的指针ps作为参数,并不返回任何值(即返回类型为void)。

  1. 检查栈是否为空:首先,使用assert宏和StackEmpty函数来确保栈不为空。如果栈为空,则StackEmpty(ps)将返回true(或非零值),导致assert失败,并可能终止程序(这取决于assert宏的具体实现和编译器的设置)。这是一种调试时的安全措施,用于防止对空栈进行出栈操作。

  2. 出栈操作:在确认栈不为空后,通过将栈顶位置ps->top减1来实现出栈操作。这实际上是将栈顶指针向下移动一位,从而“移除”了栈顶元素(但请注意,元素的值仍然保留在内存中,只是不再被视为栈的一部分)。

 函数代码:

#include <assert.h> // 包含头文件以支持assert宏  
#include "stack.h"  // 假设StackEmpty函数和ST结构体定义在这个头文件中  void StackPop(ST* ps)  
{  assert(!StackEmpty(ps)); // 确保栈不为空  --ps->top; // 将栈顶位置减1,实现出栈操作  
}

取栈顶元素

StackTop函数用于获取栈顶元素的值,但不移除该元素。它接收一个指向栈的指针ps作为参数,并返回栈顶元素的值。

  1. 检查栈是否为空:首先,使用assert宏和StackEmpty函数来确保栈不为空。如果栈为空,则StackEmpty(ps)将返回true(或非零值),导致assert失败,可能会终止程序(这取决于assert宏的具体实现和编译器的设置)。这是一种调试时的安全措施,用于防止对空栈进行取栈顶元素操作。

  2. 获取栈顶元素:在确认栈不为空后,通过访问栈数组ps->arr中栈顶位置ps->top的前一个元素(即ps->arr[ps->top - 1])来获取栈顶元素的值。由于栈顶位置ps->top是指向栈中下一个空位置的索引,因此栈顶元素实际上是位于ps->top - 1的索引处。

  3. 返回栈顶元素的值:最后,函数返回栈顶元素的值。

 函数代码:

#include <assert.h> // 包含头文件以支持assert宏  
#include "stack.h"  // 假设StackEmpty函数、ST结构体和STDataType类型定义在这个头文件中  STDataType StackTop(ST* ps)  
{  assert(!StackEmpty(ps)); // 确保栈不为空  return ps->arr[ps->top - 1]; // 返回栈顶元素的值  
}

销毁

STDestroy函数用于释放栈所占用的内存资源,并将栈结构体成员重置为初始状态。它接收一个指向栈的指针ps作为参数,并不返回任何值(即返回类型为void)。

  1. 释放栈数组内存:首先,函数检查栈数组指针ps->arr是否不为NULL。如果不为NULL,说明栈数组已经分配了内存,因此使用free函数释放这块内存。这是为了防止内存泄漏,即程序不再需要的内存没有被释放回系统。

  2. 重置栈结构体成员:在释放栈数组内存后,函数将栈结构体成员ps->arr重置为NULL,表示栈数组指针不再指向任何有效的内存区域。同时,将栈的容量ps->capacity和栈顶位置ps->top都重置为0,表示栈现在是空的,且没有分配任何内存。

函数代码:

#include <stdlib.h> // 包含头文件以支持free函数  
#include "stack.h"  // 假设ST结构体定义在这个头文件中  void STDestroy(ST* ps)  
{  if (ps->arr != NULL)  free(ps->arr); // 释放栈数组内存  ps->arr = NULL;    // 重置栈数组指针为NULL  ps->capacity = 0;  // 重置栈容量为0  ps->top = 0;       // 重置栈顶位置为0  
}

四.链栈的实现

定义链栈的结构

我们定义了两个主要结构来支持链栈的实现:

链栈节点结构 (StackNode):

  • STDataType data;:存储节点中的数据,STDataType 在此例中为 int 类型。
  • struct StackNode* next;:指向链栈中下一个节点的指针。若当前节点为链栈末尾,则此指针为 NULL

链栈结构 (LinkedStack):

  • StackNode* top;:栈顶指针,指向链栈的顶部节点(即最后压入的节点)。若链栈为空,则此指针为 NULL
  • // int capacity;:对于链栈,由于其容量是动态的(随着节点的添加和删除而变化),因此这个容量字段在此场景中通常不需要。它已被注释掉,表明在链栈的实现中不考虑此字段。

链栈(或链式栈)是基于链表实现的栈数据结构,它不需要预先分配固定大小的内存空间,能够动态地增长和缩小。数据压入(push)时,新节点被添加到栈顶;数据弹出(pop)时,栈顶节点被移除。

函数代码:

// 定义栈的数据类型  
typedef int STDataType;// 定义链栈的节点结构  
typedef struct StackNode {STDataType data;struct StackNode* next;
} StackNode;// 定义链栈的结构,包含栈顶指针和栈的容量(对于链栈,容量通常不是必需的,但这里为了完整性保留)  
typedef struct LinkedStack {StackNode* top;// int capacity; // 对于链栈,容量是动态的,因此不需要这个字段  
} LinkedStack;

初始化

函数名:initStack

目的:初始化链栈,确保栈顶指针指向NULL,从而表明链栈当前为空。

参数:LinkedStack* stack,这是一个指向链栈结构体的指针,用于访问和修改链栈的状态。

函数体详细解析:

 stack->top = NULL;

  • 这行代码执行了链栈初始化的核心操作。
  • stack->top 是对链栈结构体中栈顶指针成员的访问。
  • 将 stack->top 设置为 NULL 表示链栈当前不包含任何节点,即栈为空。

函数代码:

// 初始化链栈  
void initStack(LinkedStack* stack) {stack->top = NULL; // 栈顶指针初始化为NULL,表示空栈  
}

 入栈

函数名:push

目的:将新数据压入链栈中,使其成为栈顶元素。

参数:

  • LinkedStack* stack:指向链栈结构体的指针,用于访问和修改链栈的状态。
  • STDataType data:要压入链栈的数据。

函数体详细解析:

  1. 创建新节点
    • StackNode* newNode = (StackNode*)malloc(sizeof(StackNode));
    • 这行代码通过malloc函数动态分配内存,用于存储新节点。
    • sizeof(StackNode)计算了StackNode结构体所需的内存大小。
    • (StackNode*)是类型转换,将void*类型的malloc返回值转换为StackNode*类型。
  2. 内存分配失败处理
    • 检查newNode是否为NULL,以判断内存分配是否成功。
    • 若内存分配失败,则打印错误信息并退出程序。
  3. 设置新节点的数据
    • newNode->data = data;
    • 将函数参数data的值赋给新节点的data成员。
  4. 链接新节点到链栈
    • newNode->next = stack->top;
    • 将新节点的next指针指向当前的栈顶节点。
    • 这一步实现了链栈的“后进先出”(LIFO)特性,因为新节点被放在了链栈的顶部。
  5. 更新栈顶指针
    • stack->top = newNode;
    • 将栈顶指针指向新节点,完成压栈操作。

函数代码:

// 压栈操作  
void push(LinkedStack* stack, STDataType data) {StackNode* newNode = (StackNode*)malloc(sizeof(StackNode)); // 创建新节点  if (!newNode) {printf("Memory allocation failed\n");exit(EXIT_FAILURE);}newNode->data = data; // 设置新节点的数据  newNode->next = stack->top; // 新节点的next指向当前的栈顶节点  stack->top = newNode; // 栈顶指针指向新节点  
}

检查栈是否为空

函数名:isEmpty

目的:判断链栈是否为空。

参数:LinkedStack* stack,指向链栈结构体的指针,用于访问链栈的栈顶指针。

函数体详细解析:

  1. 判断链栈是否为空
    • return stack->top == NULL;
    • 这行代码通过比较栈顶指针stack->top是否为NULL来判断链栈是否为空。
    • stack->topNULL,则链栈为空,函数返回1
    • stack->top不为NULL,则链栈不为空,函数返回0

函数代码:

// 判断链栈是否为空  
int isEmpty(LinkedStack* stack) {return stack->top == NULL;
}

出栈

函数名称:pop

函数目的:从链栈中移除栈顶元素,并返回该元素的数据。

函数参数:

  • LinkedStack* stack:指向链栈结构体的指针,包含了链栈的栈顶指针和可能的其他管理信息。

函数返回值:

  • STDataType:被移除的栈顶元素的数据。

函数体解析:

  1. 检查链栈是否为空
    • if (isEmpty(stack)) { ... }
      • 调用isEmpty函数检查链栈是否为空。
      • 如果链栈为空,则打印错误信息“Stack underflow”,表示尝试从空栈中出栈。
      • 通过exit(EXIT_FAILURE)终止程序。这是一种错误处理方式,也可以选择返回一个特殊值来表示错误,但这里选择直接退出程序。
  2. 移除栈顶元素
    • StackNode* tempNode = stack->top;
      • 创建一个临时指针tempNode,并将其指向当前的栈顶节点。
    • STDataType poppedData = tempNode->data;
      • 从栈顶节点中获取数据,并将其存储在局部变量poppedData中。
    • stack->top = tempNode->next;
      • 将栈顶指针更新为指向下一个节点,这样原来的栈顶节点就被从链栈中移除了。
  3. 释放内存
    • free(tempNode);
    • 释放之前被移除的栈顶节点的内存。这是内存管理的重要步骤,防止内存泄漏。
  4. 返回数据
    • return poppedData;
      • 返回被移除的栈顶元素的数据。

函数代码:

// 出栈操作  
STDataType pop(LinkedStack* stack) {if (isEmpty(stack)) {printf("Stack underflow\n");exit(EXIT_FAILURE); // 或者返回一个特殊值表示错误,这里选择退出程序  }StackNode* tempNode = stack->top; // 临时节点指向栈顶节点  STDataType poppedData = tempNode->data; // 获取栈顶节点的数据  stack->top = tempNode->next; // 栈顶指针指向下一个节点  free(tempNode); // 释放栈顶节点的内存  return poppedData; // 返回出栈的数据  
}

销毁

函数名称destroyStack

函数目的:释放链栈中所有节点的内存,从而销毁链栈。

函数参数

  • LinkedStack* stack:指向链栈结构体的指针,包含了链栈的栈顶指针和可能的其他管理信息。

函数解析

destroyStack函数通过循环调用pop函数来逐个移除链栈中的节点,并在每次移除节点时释放其内存。这个过程会一直持续到链栈为空。

  1. 循环检查链栈是否为空
    • 使用while (!isEmpty(stack))循环,只要链栈不为空,就继续执行循环体内的操作。
  2. 出栈操作
    • 在循环体内,调用pop(stack)函数。pop函数会移除链栈的栈顶节点,并释放其内存。同时,pop函数还会返回被移除节点的数据,但在destroyStack函数中,我们并不关心这个返回值。
  3. 无需额外销毁操作
    • 由于pop函数已经负责释放了所有节点的内存,因此destroyStack函数本身不需要进行额外的销毁操作。但是,为了保持接口的一致性(例如,与其他数据结构的销毁函数保持类似的签名),destroyStack函数还是被保留了下来。
  4. 函数结束
    • 当链栈为空时,isEmpty(stack)将返回truewhile循环将终止,destroyStack函数也随之结束。此时,链栈中的所有节点都已经被释放,链栈已被销毁。

函数代码:

// 销毁链栈(释放所有节点的内存)  
void destroyStack(LinkedStack* stack) {while (!isEmpty(stack)) {pop(stack); // 通过出栈操作释放所有节点的内存  }// 对于链栈,由于我们已经在出栈时释放了所有节点的内存,因此不需要额外的销毁操作  // 但为了保持接口的一致性,这里还是保留了这个函数  
}

兄弟们共勉!!!  

码字不易,求个三连

抱拳了兄弟们!

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

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

相关文章

新版idea菜单栏展开与合并

新版idea把菜单栏合并了看着很是不习惯&#xff0c;找了半天原来在这里展开 ① 点击文件 -> 设置 ② 点击外观与行为 -> 外观 -> 合并主菜单和窗口标题 然后确定&#xff0c;重启即可

戴维南,叠加,稳态笔记

一点点学习笔记,仅做个人复习使用 节点电压分清电流电压源&#xff0c;电流源才能写在右边&#xff0c;容易混淆 叠加定理仅适用于线性电路&#xff0c;且不能用于计算功率&#xff0c;主要是方向&#xff0c;要看源的方向判断等效之后的&#xff0c;受控源不参与除源&#x…

数据库表的创建

运用的环境是pychram python3.11.4 创建一个表需要用到以下语法 注释已经写清楚各种语法的含义&#xff0c;记住缩进是你程序运行的关键&#xff0c;因为程序是看你的缩进来判断你的运行逻辑&#xff0c;像我这个就是缩进不合理导致的报错 那么今天分享就到这里&#xff0c;谢…

android11 usb摄像头添加多分辨率支持

部分借鉴于&#xff1a;https://blog.csdn.net/weixin_45639314/article/details/142210634 目录 一、需求介绍 二、UVC介绍 三、解析 四、补丁修改 1、预览的限制主要存在于hal层和framework层 2、添加所需要的分辨率&#xff1a; 3、hal层修改 4、frameworks 5、备…

第九届清洁能源与发电技术国际学术会议(CEPGT 2024)

第九届清洁能源与发电技术国际学术会议&#xff08;CEPGT 2024&#xff09; 2024 9th International Conference on Clean Energy and Power Generation Technology (CEPGT 2024) 【早投稿早录用&#xff0c;享受早鸟优惠】 CEPGT 2024会议已上线至IEEE官网 第九届清洁能源…

15分钟学Go 第2天:安装Go环境

第2天&#xff1a;安装Go环境 1. 引言 在学习Go语言之前&#xff0c;首先需要配置好本地开发环境。本节将详细介绍如何在Windows 11上安装和配置Go语言环境&#xff0c;包括安装步骤、环境变量设置、VS Code配置与测试、以及常见问题解决方案。完成这些步骤后&#xff0c;你将…

Java项目-基于springboot框架的基于协同过滤算法商品推荐系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

Kettle9.4支持Clickhouse数据源插件开发以及性能测试

前言 最近业务这边有个指标需要用到大数据这边的列式数据库进行处理&#xff0c;由于kettle不支持clickhouse数据源驱动&#xff0c;这里查了一下网上的相关资料&#xff0c;发现了一些别人开发好的驱动包&#xff0c;下载下来后使用效果不尽人意。总结下来有以下几个问题&…

quic-go源码一---server启动

前言&#xff1a; 走马观花地看了RFC 9000:QUIC: A UDP-Based Multiplexed and Secure Transport&#xff0c; 感受不是那么直观&#xff0c;所以再来看看这个协议的golang语言实现&#xff1a;quic-go,加强学习。 https://quic-go.net/docs/quic/quic-go文档 本篇准备的代…

基于R语言机器学习方法在生态经济学领域中技术应用

近年来&#xff0c;人工智能领域已经取得突破性进展&#xff0c;对经济社会各个领域都产生了重大影响&#xff0c;结合了统计学、数据科学和计算机科学的机器学习是人工智能的主流方向之一&#xff0c;目前也在飞快的融入计量经济学研究。表面上机器学习通常使用大数据&#xf…

证件照小程序源码,前后端稳定运行

演示&#xff1a;证寸照制作 运行环境: Linux Nginx PHP >5.6 MySQL>5.6 安装步骤: 1.下载源码上传至你的服务器宝塔面板 2.直接添加站点选择源码目录&#xff0c;新建数据库 3.设置代码执行目录为/web 4.在浏览器中输入你的域名&#xff0c;会提示安装&#xff0c;填写…

SpringBoot02:第一个springboot程序

3、第一个springboot程序 3.1、准备工作 我们将学习如何快速的创建一个Spring Boot应用&#xff0c;并且实现一个简单的Http请求处理。通过这个例子对Spring Boot有一个初步的了解&#xff0c;并体验其结构简单、开发快速的特性。 我的环境准备&#xff1a; java version "…

智能优化算法-禁忌搜索算法(TS)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1.内容介绍 禁忌搜索优化算法 (Tabu Search, TS) 是一种基于局部搜索的元启发式优化算法&#xff0c;由Fred Glover于1986年提出。TS通过引入“禁忌表”来避免重复搜索已经访问过的解&#xff0c;从而跳出局部最优解&#…

十四、MySQL事务日志

文章目录 1. redo日志1.1 为什么需要REDO日志1.2 REDO日志的好处、特点1.2.1 好处1.2.2 特点1.3 redo的组成1.4 redo的整体流程1.5 redo log 的刷盘策略1.6 不同刷盘策略演示1.7 写入redo log buffer 过程1.7.1 补充概念:Mini-Transaction1.7.2 redo 日志写入log buffer1.7.3 …

[DB] NSM

Database Workloads&#xff08;数据库工作负载&#xff09; 数据库工作负载指的是数据库在执行不同类型任务时所需的资源和计算方式&#xff0c;主要包括以下几种类型&#xff1a; 1. On-Line Transaction Processing (OLTP) 中文&#xff1a;联机事务处理解释&#xff1a;…

如何使用DockerSpy检测你的Docker镜像是否安全

关于DockerSpy DockerSpy是一款针对Docker镜像的敏感信息检测与安全审计工具&#xff0c;该工具可以帮助广大研究人员在Docker Hub上检测和搜索自己镜像的安全问题&#xff0c;并识别潜在的泄漏内容&#xff0c;例如身份验证密钥等敏感信息。 功能介绍 1、安全审计&#xff1a…

基于yolov10的驾驶员抽烟打电话安全带检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv10的驾驶员抽烟、打电话、安全带检测系统是一种先进的驾驶行为监测系统。该系统利用YOLOv10算法的高效性和准确性&#xff0c;实现对驾驶员行为的实时检测与识别。 YOLOv10是一种最新的实时物体检测模型&#xff0c;其通过深度学习技术&#xff0c;如卷…

【网络原理】HTTP协议

目录 前言 一.什么是HTTP HTTP报文格式 HTTP的请求格式 1.首行 2.请求头&#xff08;header&#xff09; 3.空行 4.正文&#xff08;body&#xff09; HTTP的响应格式 1.首行 2.响应头 3.空行 4.正文&#xff08;body&#xff09; 首行中的方法 GET和POST的区别 …

使用Radzen Blazor组件库开发的基于ABP框架炫酷UI主题

一、项目简介 使用过ABP框架的童鞋应该知道它也自带了一款免费的Blazor UI主题&#xff0c;它的页面是长这样的&#xff1a; 个人感觉不太美观&#xff0c;于是网上搜了很多Blazor开源组件库&#xff0c;发现有一款样式非常不错的组件库&#xff0c;名叫&#xff1a;Radzen&am…

[渗透]前端源码Chrome浏览器修改并运行

文章目录 简述本项目所使用的代码[Fir](https://so.csdn.net/so/search?qFir&spm1001.2101.3001.7020) Cloud 完整项目 原始页面修改源码本地运行前端源码修改页面布局修改请求接口 本项目请求方式 简述 好久之前&#xff0c;就已经看到&#xff0c;_无论什么样的加密&am…