数据结构:栈(Stack)及其实现
栈(Stack)是计算机科学中常用的一种数据结构,它遵循先进后出(Last In, First Out,LIFO)的原则。也就是说,栈中的元素只能从栈顶进行访问,最后放入栈中的元素最先被取出。栈在很多应用中非常重要,例如函数调用、表达式求值、深度优先搜索等。
本文将介绍栈的基本概念、实现逻辑,并通过C语言代码演示栈的常见操作。
1. 栈的基本概念
栈是一种线性数据结构,其主要操作包括:
- 压栈(Push):将一个元素压入栈顶。
- 弹栈(Pop):从栈顶移除一个元素。
- 栈顶元素(Top/Peek):获取栈顶的元素,但不移除它。
- 栈空(IsEmpty):检查栈是否为空。
- 栈满(IsFull):检查栈是否已满(对于固定大小的栈)。
栈的特点是只能从栈顶进行操作,所有元素的插入和删除都发生在栈顶。
2. 栈的实现逻辑
栈的实现可以基于数组或链表。这里我们采用数组实现栈,并且实现栈的常见操作。
- 栈的初始化:栈需要一个数组来存储元素,并且需要一个指针
top
来指示栈顶的位置。 - 压栈操作(Push):将元素放入栈顶,
top
指针向上移动。 - 弹栈操作(Pop):移除栈顶元素,
top
指针向下移动。 - 查看栈顶元素(Top/Peek):返回
top
指针位置的元素。 - 检查栈空(IsEmpty):判断
top
是否为-1,栈为空时top = -1
。 - 检查栈满(IsFull):判断
top
是否等于栈的最大容量减1。
3. C语言实现栈
#include <stdio.h>
#include <stdlib.h>#define MAX 5 // 栈的最大容量// 栈结构体
typedef struct {int arr[MAX]; // 存储栈元素的数组int top; // 栈顶指针
} Stack;// 栈初始化函数
void initStack(Stack* stack) {stack->top = -1; // 初始时栈为空,栈顶指针为-1
}// 判断栈是否为空
int isEmpty(Stack* stack) {return stack->top == -1; // 如果栈顶指针为-1,说明栈为空
}// 判断栈是否为满
int isFull(Stack* stack) {return stack->top == MAX - 1; // 如果栈顶指针为MAX-1,说明栈已满
}// 压栈操作
void push(Stack* stack, int value) {if (isFull(stack)) {printf("栈满,无法压栈!\n");return;}stack->arr[++(stack->top)] = value; // 将元素放入栈顶,并更新栈顶指针printf("元素 %d 压栈成功!\n", value);
}// 弹栈操作
int pop(Stack* stack) {if (isEmpty(stack)) {printf("栈空,无法弹栈!\n");return -1;}return stack->arr[(stack->top)--]; // 返回栈顶元素,并更新栈顶指针
}// 获取栈顶元素
int peek(Stack* stack) {if (isEmpty(stack)) {printf("栈空,无法获取栈顶元素!\n");return -1;}return stack->arr[stack->top]; // 返回栈顶元素
}// 打印栈的所有元素
void printStack(Stack* stack) {if (isEmpty(stack)) {printf("栈空,无法打印栈元素!\n");return;}printf("栈内元素:");for (int i = 0; i <= stack->top; i++) {printf("%d ", stack->arr[i]);}printf("\n");
}int main() {Stack stack;initStack(&stack); // 初始化栈// 压栈操作push(&stack, 10);push(&stack, 20);push(&stack, 30);push(&stack, 40);push(&stack, 50);// 打印栈元素printStack(&stack);// 再压栈时,栈满的情况push(&stack, 60);// 弹栈操作printf("弹栈元素: %d\n", pop(&stack));printf("弹栈元素: %d\n", pop(&stack));// 打印栈元素printStack(&stack);// 查看栈顶元素printf("栈顶元素: %d\n", peek(&stack));return 0;
}
4. 代码注释说明
-
栈的结构体:
Stack
结构体包含了一个大小为MAX
的数组arr
来存储栈元素,以及一个top
变量来记录栈顶的位置。top
的初始值为-1
,表示栈为空。 -
initStack
函数:初始化栈,将top
设为-1
,表示栈为空。 -
isEmpty
函数:判断栈是否为空。如果top
为-1
,返回1
表示栈空;否则返回0
。 -
isFull
函数:判断栈是否为满。如果top
等于MAX-1
,说明栈已满,返回1
表示栈满;否则返回0
。 -
push
函数:将元素压入栈顶,首先检查栈是否已满,如果未满,top
指针加1,然后将元素放入栈顶。 -
pop
函数:从栈顶移除元素,首先检查栈是否为空,如果栈不为空,返回栈顶元素并将top
指针减1。 -
peek
函数:查看栈顶元素,但不移除它。首先检查栈是否为空,如果不为空,返回栈顶元素。 -
printStack
函数:打印栈中所有的元素。首先检查栈是否为空,如果栈不为空,则依次打印从栈底到栈顶的所有元素。 -
5. 运行示例
假设我们运行上述程序,输出结果如下:
元素 10 压栈成功!
元素 20 压栈成功!
元素 30 压栈成功!
元素 40 压栈成功!
元素 50 压栈成功!
栈内元素:10 20 30 40 50
栈满,无法压栈!
弹栈元素: 50
弹栈元素: 40
栈内元素:10 20 30
栈顶元素: 30
- 初始时,栈为空,通过压栈操作逐步将元素
10, 20, 30, 40, 50
压入栈中。 - 然后尝试压栈一个新的元素
60
,由于栈已满,无法压栈。 - 接着,弹出栈顶元素
50
和40
,并打印当前栈中的元素。 - 最后,查看栈顶元素
30
。
6.栈在实际应用中的一些常见使用场景
6.1. 函数调用和递归
栈最常见的应用之一是函数调用,它在计算机的程序执行过程中被广泛使用。
实现过程:
当程序调用一个函数时,程序会将当前函数的执行状态(如局部变量、返回地址等)保存在栈中,这个过程叫做“入栈”。
- 当一个函数调用另一个函数时,栈会继续“压入”当前函数的状态。
- 当一个函数执行完毕,栈会“弹出”当前函数的状态,并恢复到上一个函数的执行状态。
这种机制是通过栈来实现的,也就是函数调用栈。当递归调用发生时,每次递归调用都将当前的执行环境推入栈中,直到递归结束并返回时,栈中的元素逐步弹出,恢复到原来的状态。
示例:
递归计算斐波那契数列时,栈用于存储每次递归调用的状态。
int fibonacci(int n) {if (n <= 1) {return n;}return fibonacci(n-1) + fibonacci(n-2);
}
每次fibonacci
函数调用时,程序都会把当前调用的返回地址和局部变量压入栈中。栈的大小随着递归深度的增加而增加,直到递归返回时,栈逐一弹出,恢复状态。
6.2. 表达式求值
栈是计算机中表达式求值的常用工具,特别是在处理后缀表达式(逆波兰表示法)和前缀表达式时。
后缀表达式(逆波兰表示法):
例如,给定一个表达式3 4 + 5 *
,可以通过栈来实现求值。
- 遇到操作数(如3、4),将其压入栈。
- 遇到操作符(如+、*),弹出栈顶的两个操作数,进行计算,然后将结果重新压入栈。
- 最终栈中剩下的就是结果。
示例:
例如计算表达式3 4 + 5 *
:
- 第一步:遇到
3
和4
,压栈,栈为[3, 4]
。 - 第二步:遇到
+
,弹出栈顶的两个数4
和3
,计算3 + 4 = 7
,将结果压入栈,栈为[7]
。 - 第三步:遇到
5
,压栈,栈为[7, 5]
。 - 第四步:遇到
*
,弹出栈顶的两个数5
和7
,计算7 * 5 = 35
,将结果压入栈,栈为[35]
。
最终栈中的元素即为结果35
。
6.3. 括号匹配
栈常用于括号匹配问题,特别是在编译器和解释器中,栈是检查是否存在匹配括号的一种有效方式。
实现过程:
通过栈可以有效地检查括号的匹配情况,例如:
- 遇到一个左括号
(
时,将其压入栈中。 - 遇到右括号
)
时,弹出栈顶元素,并确保栈中存在对应的左括号(
。 - 如果栈为空或者遇到不匹配的括号,则说明括号不匹配。
示例:
检查括号匹配的代码:
#include <stdio.h>
#include <stdbool.h>#define MAX 100typedef struct {char items[MAX];int top;
} Stack;void initStack(Stack* stack) {stack->top = -1;
}bool isEmpty(Stack* stack) {return stack->top == -1;
}void push(Stack* stack, char value) {stack->items[++(stack->top)] = value;
}char pop(Stack* stack) {return stack->items[(stack->top)--];
}bool isValid(char* s) {Stack stack;initStack(&stack);for (int i = 0; s[i] != '\0'; i++) {if (s[i] == '(') {push(&stack, s[i]);} else if (s[i] == ')') {if (isEmpty(&stack)) {return false; // 没有匹配的左括号}pop(&stack); // 弹出栈顶左括号}}return isEmpty(&stack); // 如果栈为空,说明所有括号匹配
}int main() {char s[] = "(())";if (isValid(s)) {printf("括号匹配!\n");} else {printf("括号不匹配!\n");}return 0;
}
6.4. 浏览器历史记录和撤销操作
栈还被广泛用于实现浏览器的历史记录和撤销操作,这是由于栈的后进先出(LIFO)特性。
浏览器历史记录:
浏览器通过栈来保存用户访问的网页,每访问一个新网页时,当前网页的URL会被压入栈中,用户点击"后退"按钮时,浏览器会从栈顶弹出上一个网页的URL,展示该页面。
撤销操作:
例如在文本编辑器中,栈用于保存操作记录(如文本插入、删除等),当用户点击"撤销"时,可以通过弹出栈顶的操作记录来撤销最近的操作。
6.5. 深度优先搜索(DFS)
栈是深度优先搜索(DFS)算法的基础。在图的遍历中,深度优先搜索使用栈来存储待访问的节点,直到访问完所有可能的节点。
实现过程:
- 从某个节点开始,访问该节点并将其压入栈中。
- 然后遍历该节点的所有未访问的邻居,将它们压入栈中。
- 每次弹出栈顶节点,继续遍历该节点的邻居,直到栈为空为止。
这种方式常用于遍历无向图、有向图或解决迷宫问题等。
6.6. 逆序操作
栈可以用于实现逆序操作,例如将一个序列反转。
实现过程:
通过将序列中的元素压入栈中,然后再从栈中逐个弹出元素,这样就能得到一个逆序的序列。
示例:
反转字符串的代码:
#include <stdio.h>
#include <string.h>#define MAX 100typedef struct {char items[MAX];int top;
} Stack;void initStack(Stack* stack) {stack->top = -1;
}void push(Stack* stack, char value) {stack->items[++(stack->top)] = value;
}char pop(Stack* stack) {return stack->items[(stack->top)--];
}void reverseString(char* str) {Stack stack;initStack(&stack);int length = strlen(str);// 将字符串字符压入栈for (int i = 0; i < length; i++) {push(&stack, str[i]);}// 从栈中弹出字符,形成逆序字符串for (int i = 0; i < length; i++) {str[i] = pop(&stack);}
}int main() {char str[] = "Hello, World!";reverseString(str);printf("逆序字符串: %s\n", str);return 0;
}
7. 总结
-
栈是一种遵循LIFO(先进后出)原则的线性数据结构,它的常见应用包括递归函数调用、表达式求值、括号匹配等。本文通过C语言实现了一个基于数组的栈,演示了栈的基本操作:压栈、弹栈、查看栈顶元素、判断栈空和栈满,并附上了详细的注释。栈是一种非常简单但功能强大的数据结构,理解栈的基本操作和应用场景对于学习计算机科学非常重要。
-
栈作为一种数据结构,在许多计算机科学和实际应用中都扮演着重要的角色。其最典型的应用包括:
-
函数调用和递归。
-
表达式求值。
-
括号匹配。
-
浏览器历史记录和撤销操作。
-
深度优先搜索。
-
逆序操作。
版权声明:本文为原创文章,转载请注明出处。
相关文章:
数据结构:栈(Stack)及其实现
栈(Stack)是计算机科学中常用的一种数据结构,它遵循先进后出(Last In, First Out,LIFO)的原则。也就是说,栈中的元素只能从栈顶进行访问,最后放入栈中的元素最先被取出。栈在很多应用…...
DeepSeek在linux下的安装部署与应用测试
结合上一篇文章,本篇文章主要讲述在Redhat linux环境下如何部署和使用DeepSeek大模型,主要包括ollama的安装配置、大模型的加载和应用测试。关于Open WebUI在docker的安装部署,Open WebUI官网也提供了完整的docker部署说明,大家可…...
Next.js【详解】获取数据(访问接口)
Next.js 中分为 服务端组件 和 客户端组件,内置的获取数据各不相同 服务端组件 方式1 – 使用 fetch export default async function Page() {const data await fetch(https://api.vercel.app/blog)const posts await data.json()return (<ul>{posts.map((…...
pnpm, eslint, vue-router4, element-plus, pinia
利用 pnpm 创建 vue3 项目 pnpm 包管理器 - 创建项目 Eslint 配置代码风格(Eslint用于规范纠错,prettier用于美观) 在 设置 中配置保存时自动修复 提交前做代码检查 husky是一个 git hooks工具(git的钩子工具,可以在特定实际执行特…...
将jar安装到Maven本地仓库中
将jar安装到Maven本地仓库中 1. 使用 mvn install:install-file 命令模版示例 2.项目中添加依赖 将一个 .jar 文件安装到 Maven 本地仓库中是一个常见的操作,尤其是在你想要在本地测试一个尚未发布到中央仓库的库时。以下是如何将 .jar 文件安装到 Maven 本地仓库的…...
Spring 和 Spring MVC 的关系是什么?
Spring和Spring MVC的关系就像是“大家庭和家里的小书房”一样。 Spring是一个大家庭,提供了各种各样的功能和服务,比如管理Bean的生命周期、事务管理、安全性等,它是企业级应用开发的全方位解决方案。这个大家庭里有很多房间,每个…...
Ollama ModelFile(模型文件)
1. 什么是 Modelfile? Modelfile 是 Ollama 的配置文件,用于定义和自定义模型的行为。通过它,你可以: 基于现有模型(如 llama2、mistral)创建自定义版本 调整生成参数(如温度、重复惩罚&#…...
基于python深度学习遥感影像地物分类与目标识别、分割实践技术应用
我国高分辨率对地观测系统重大专项已全面启动,高空间、高光谱、高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成,将成为保障国家安全的基础性和战略性资源。未来10年全球每天获取的观测数据将超过10PB,遥感大数据时…...
(蓝桥杯——10. 小郑做志愿者)洛斯里克城志愿者问题详解
题目背景 小郑是一名大学生,她决定通过做志愿者来增加自己的综合分。她的任务是帮助游客解决交通困难的问题。洛斯里克城是一个六朝古都,拥有 N 个区域和古老的地铁系统。地铁线路覆盖了树形结构上的某些路径,游客会询问两个区域是否可以通过某条地铁线路直达,以及有多少条…...
基于 Ollama 工具的 LLM 大语言模型如何部署,以 DeepSeek 14B 本地部署为例
简简单单 Online zuozuo :本心、输入输出、结果 文章目录 基于 Ollama 工具的 LLM 大语言模型如何部署,以 DeepSeek 14B 本地部署为例前言下载 Ollama实际部署所需的硬件要求设置 LLM 使用 GPU ,发挥 100% GPU 性能Ollama 大模型管理命令大模型的实际运行资源消耗基于 Ollam…...
大模型工具大比拼:SGLang、Ollama、VLLM、LLaMA.cpp 如何选择?
简介:在人工智能飞速发展的今天,大模型已经成为推动技术革新的核心力量。无论是智能客服、内容创作,还是科研辅助、代码生成,大模型的身影无处不在。然而,面对市场上琳琅满目的工具,如何挑选最适合自己的那…...
【05】密码学与隐私保护
5-1 零知识证明 零知识证明介绍 零知识证明的概念 设P(Prover)表示掌握某些信息,并希望证实这一事实的实体,V(Verifier)是验证这一事实的实体。 零知识证明是指P试图使V相信某一个论断是正确的,但却不向…...
Flink SQL与Doris实时数仓Join实战教程(理论+实例保姆级教程)
目录 第一章:Regular Joins 深度解析 1.1 核心原理与适用场景 1.2 电商订单 - 商品实时关联案例 1.2.1 数据流设计 1.2.2 Doris 表设计优化 1.2.3 性能调优要点 第二章:Interval Joins 实战应用 2.1 时间区间关联原理 2.2 优惠券使用有效性验证 2.2.1 业务场景说明 …...
DeepSeek 助力 Vue 开发:打造丝滑的范围选择器(Range Picker)
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…...
68页PDF | 数据安全总体解决方案:从数据管理方法论到落地实践的全方位指南(附下载)
一、前言 这份报告旨在应对数字化转型过程中数据安全面临的挑战,并提供全面的管理与技术体系建设框架。报告首先分析了数字化社会的发展背景,强调了数据安全在国家安全层面的重要性,并指出数据安全风险的来源和防护措施。接着,报…...
【Github每日推荐】-- 2024 年项目汇总
1、AI 技术 项目简述OmniParser一款基于纯视觉的 GUI 智能体,能够准确识别界面上可交互图标以及理解截图中各元素语义,实现自动化界面交互场景,如自动化测试、自动化操作等。ChatTTS一款专门为对话场景设计的语音生成模型,主要用…...
【Spring详解一】Spring整体架构和环境搭建
一、Spring整体架构和环境搭建 1.1 Spring的整体架构 Spring框架是一个分层架构,包含一系列功能要素,被分为大约20个模块 Spring核心容器:包含Core、Bean、Context、Expression Language模块 Core :其他组件的基本核心ÿ…...
Spring Boot(8)深入理解 @Autowired 注解:使用场景与实战示例
搞个引言 在 Spring 框架的开发中,依赖注入(Dependency Injection,简称 DI)是它的一个核心特性,它能够让代码更加模块化、可测试,并且易于维护。而 Autowired 注解作为 Spring 实现依赖注入的关键工具&…...
Machine Learning:Optimization
文章目录 局部最小值与鞍点 (Local Minimum & Saddle Point)临界点及其种类判断临界值种类 批量与动量(Batch & Momentum)批量大小对梯度下降的影响动量法 自适应学习率AdaGradRMSPropAdam 学习率调度优化总结 局部最小值与鞍点 (Local Minimum & Saddle Point) 我…...
wordpress get_footer();与wp_footer();的区别的关系
在WordPress中,get_footer() 和 wp_footer() 是两个不同的函数,它们在主题开发中扮演着不同的角色,但都与页面的“页脚”部分有关。以下是它们的区别和关系: 1. get_footer() get_footer() 是一个用于加载页脚模板的函数。它的主…...
Windows Docker运行Implicit-SVSDF-Planner
Windows Docker运行GitHub - ZJU-FAST-Lab/Implicit-SVSDF-Planner: [SIGGRAPH 2024 & TOG] 1. 设置环境 我将项目git clone在D:/Github目录中。 下载ubuntu20.04 noetic镜像 docker pull osrf/ros:noetic-desktop-full-focal 启动容器,挂载主机的D:/Github文…...
设计模式14:职责链模式
系列总链接:《大话设计模式》学习记录_net 大话设计-CSDN博客 1.概述 职责链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许将请求沿着处理者链传递,直到有一个处理者能够处理该请求。这种模式通过…...
Golang GORM系列:GORM并发与连接池
GORM 是一个流行的 Go 语言 ORM(对象关系映射)库,用于简化数据库操作。它支持连接池和并发访问功能,这些功能对于高性能、高并发的应用场景非常重要。本文结合示例详细介绍gorm的并发处理能力,以及如何是哟个连接池提升…...
linux笔记:shell中的while、if、for语句
在Udig软件的启动脚本中使用了while循环、if语句、for循环,其他内容基本都是变量的定义,所以尝试弄懂脚本中这三部分内容,了解脚本执行过程。 (1)while循环 while do循环内容如下所示,在循环中还用了expr…...
【Java】逻辑运算符详解:、|| 与、 | 的区别及应用
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: Java 文章目录 💯前言💯一、基本概念与运算符介绍💯二、短路与与非短路与:&& 与 & 的区别1. &&:短路与(AND)2. …...
Java 设计模式之解释器模式
文章目录 Java 设计模式之解释器模式概述UML代码实现 Java 设计模式之解释器模式 概述 解释器模式(interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。如果一种特定…...
关于前后端分离跨域问题——使用DeepSeek分析查错
我前端使用ant design vue pro框架,后端使用kratos框架开发。因为之前也解决过跨域问题,正常是在后端的http请求中加入中间件,设置跨域需要通过的字段即可,代码如下所示: func NewHTTPServer(c *conf.Server, s *conf…...
Linux下ioctl的应用
文章目录 1、ioctl简介2、示例程序编写2.1、应用程序编写2.2、驱动程序编写 3、ioctl命令的构成4、测试 1、ioctl简介 ioctl(input/output control)是Linux中的一个系统调用,主要用于设备驱动程序与用户空间应用程序之间进行设备特定的输入/…...
Windows 环境下 Grafana 安装指南
目录 下载 Grafana 安装 Grafana 方法 1:使用 .msi 安装程序(推荐) 方法 2:使用 .zip 压缩包 启动 Grafana 访问 Grafana 配置 Grafana(可选) 卸载 Grafana(如果需要) 下载 G…...
【操作系统】操作系统概述
操作系统概述 1.1 操作系统的概念1.1.1 操作系统定义——什么是OS?1.1.2 操作系统作用——OS有什么用?1.1.3 操作系统地位——计算机系统中,OS处于什么地位?1.1.4 为什么学操作系统? 1.2 操作系统的历史1.2.1 操作系统…...
基于SSM+uniapp的鲜花销售小程序+LW示例参考
1.项目介绍 系统角色:管理员、商户功能模块:用户管理、商户管理、鲜花分类管理、鲜花管理、订单管理、收藏管理、购物车、充值、下单等技术选型:SSM,Vue(后端管理web),uniapp等测试环境&#x…...
第3章 .NETCore核心基础组件:3.1 .NET Core依赖注入
3.1.1 什么是控制反转、依赖注入 杨老师在书中进行了一系列的文字阐述,总结一下就是:软件设计模式中有一种叫做【控制反转】的设计模式,而依赖注入是实现这种设计模式的一个很重要的方式。也就是说学习依赖注入,是学习怎样实现控…...
排序与算法:插入排序
执行效果 插入排序的执行效果是这样的: 呃……看不懂吗?没关系,接着往下看介绍 算法介绍 插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,…...
uniapp 打包安卓 集成高德地图
接入高德地图 let vm this;uni.chooseLocation({success: function (res) {// console.log(位置名称: res.name);// console.log(详细地址: res.address);// console.log(纬度: res.latitude);// console.log(经度: res.long…...
python爬虫系列课程2:如何下载Xpath Helper
python爬虫系列课程2:如何下载Xpath Helper 一、访问极简插件官网二、点击搜索按钮三、输入xpath并点击搜索四、点击推荐下载五、将下载下来的文件解压缩六、打开扩展程序界面七、将xpath.crx文件拖入扩展程序界面一、访问极简插件官网 极简插件官网地址:https://chrome.zzz…...
win10系统上的虚拟机安装麒麟V10系统提示找不到操作系统
目录预览 一、问题描述二、原因分析三、解决方案四、参考链接 一、问题描述 win10系统上的虚拟机安装麒麟V10系统提示找不到操作系统,报错:Operating System not found 二、原因分析 国产系统,需要注意的点: 需要看你的系统类…...
基于微信小程序的宿舍报修管理系统设计与实现,SpringBoot(15500字)+Vue+毕业论文+指导搭建视频
运行环境 jdkmysqlIntelliJ IDEAmaven3微信开发者工具 项目技术SpringBoothtmlcssjsjqueryvue2uni-app 宿舍报修小程序是一个集中管理宿舍维修请求的在线平台,为学生、维修人员和管理员提供了一个便捷、高效的交互界面。以下是关于这些功能的简单介绍: …...
分布式同步锁:原理、实现与应用
分布式同步锁:原理、实现与应用 引言1. 分布式同步锁的基本概念1.1 什么是分布式同步锁?1.2 分布式锁的特性 2. 分布式锁的实现方式2.1 基于数据库的分布式锁实现原理优缺点示例 2.2 基于 Redis 的分布式锁实现原理优缺点示例Redlock 算法 2.3 基于 ZooK…...
Chrome多开终极形态解锁!「窗口管理工具+IP隔离插件
Web3项目多开,继ads指纹浏览器钱包被盗后,更多人采用原生chrome浏览器,当然对于新手,指纹浏览器每月成本也是一笔不小开支,今天逛Github发现了这样一个解决方案,作者开发了窗口管理工具IP隔离插件ÿ…...
FreeSwitch的应用类模块
FreeSWITCH 应用类模块(Applications)完整表格 模块名称功能描述mod_callcenter提供呼叫中心功能,支持队列、座席管理、监控等。mod_conference提供多方会议功能,支持音频、视频会议。mod_blacklist提供黑名单功能,阻…...
【蓝桥杯集训·每日一题2025】 AcWing 6123. 哞叫时间 python
6123. 哞叫时间 Week 1 2月18日 农夫约翰正在试图向埃尔茜描述他最喜欢的 USACO 竞赛,但她很难理解为什么他这么喜欢它。 他说「竞赛中我最喜欢的部分是贝茜说 『现在是哞哞时间』并在整个竞赛中一直哞哞叫」。 埃尔茜仍然不理解,所以农夫约翰将竞赛以…...
Unity 淡入淡出
淡入(Fade in):类似打开幕布 淡出(Fade out):类似关上幕布 方案一 使用Dotween(推荐) using DG.Tweening; using UnityEngine; using UnityEngine.UI;public class Test : MonoB…...
PBR光照模型相关知识
PBR是基于物理的光照模型,与lambert光照模型以及Blinn-Phong光照模型有所不同 一、三种光照模型的区别 原理基础 Lambert 光照模型:基于朗伯余弦定律,该定律表明,漫反射光的强度与入射光的方向和物体表面法线的夹角的余弦值成正比…...
【Go | 从0实现简单分布式缓存】-2:HTTP服务端与一致性哈希
本文目录 一、回顾1.1 复习接口 二、http标准库三、实现HTTP服务端四、一致性哈希 本文为极客兔兔“动手写分布式缓存GeeCache”学习笔记。 一、回顾 昨天已经开发了一部分项目,我们先来看看项目结构。 分布式缓存需要实现节点间通信,建立基于 HTTP 的…...
STM32 低功耗模式
目录 背景 低功耗模式 睡眠模式 进入睡眠模式 退出睡眠模式 停止模式 进入停止模式 退出停止模式 待机模式 进入待机模式 退出待机模式 程序 睡眠模式 休眠模式配置 进入休眠模式 退出睡眠模式 停止模式 停止模式配置 进入停止模式 退出停止模式 待机模式…...
AI 百炼成神:逻辑回归, 垃圾邮件分类
第二个项目:逻辑回归垃圾邮件分类 项目代码下载地址:https://download.csdn.net/download/m0_56366541/90398247 项目目标 学习逻辑回归的基本概念。使用逻辑回归算法来实现垃圾邮件的分类。理解如何处理文本数据以及如何评估分类模型的性能。项目步骤 准备数据集 我们将使…...
#渗透测试#批量漏洞挖掘#Apache Log4j反序列化命令执行漏洞
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章读。 目录 Apache Log4j反序列化命令执行漏洞 一、…...
Docker__持续更新......
Docker 1. 基本知识1.1 为什么有Docker?1.2 Docker架构与容器化 画图解释 画图解释2. 项目实战 1. 基本知识 1.1 为什么有Docker? 用一行命令跨平台安装项目,在不同平台上运行项目。把项目打包分享运行应用。 1.2 Docker架构与容器化 准备机器,在机…...
什么是语料清洗、预训练、指令微调、强化学习、内容安全; 什么是megatron,deepspeed,vllm推理加速框架
什么是语料清洗、预训练、指令微调、强化学习、内容安全 目录 什么是语料清洗、预训练、指令微调、强化学习、内容安全语料清洗预训练指令微调强化学习内容安全什么是megatron,deepspeed,vllm推理加速框架语料清洗 语料清洗是对原始文本数据进行处理的过程,旨在去除数据中的…...
Ubuntu虚拟机NDK编译ffmpeg
目录 一、ffmpeg源码下载1、安装git(用于下载ffmpeg源码)2、创建源码目录,下载ffmpeg源码 二、下载ubuntu对应的NDK,并解压到opt下1、下载并解压2、配置 ~/.bashrc 三、源码编译、1、创建编译脚本2、脚本文件内容3、设置可执行权限并运行4、编译的结果在…...