【数据结构】_栈和队列相关面试题

在这里插入图片描述
🔥 数据结构修炼场 🔥

💥 栈与队列 · 终极试炼 💥
🚀 理论已加载完毕,代码之魂觉醒时刻!
⚡️ 是时候用实战点燃你的算法之力了——

「题目风暴,来袭!」
(握紧键盘,接受挑战吧 ✨)


“Talk is cheap. Show me the code.”
                —— Linus Torvalds

1.有效的括号

题目:在这里插入图片描述

画图分析:
在这里插入图片描述

具体思路如下:

  1. 使用栈来处理括号匹配:栈是一种后进先出(LIFO)的数据结构,非常适合处理括号匹配问题。当遇到左括号([、(、{)时,将其压入栈中;当遇到右括号(]、)、})时,从栈中弹出一个左括号进行匹配。
  2. 遍历字符串:从字符串的第一个字符开始,逐个字符进行处理。
  3. 处理左括号:如果当前字符是左括号,将其压入栈中。
  4. 处理右括号:如果当前字符是右括号,检查栈是否为空。如果栈为空,说明没有对应的左括号,字符串无效;如果栈不为空,弹出栈顶元素,检查栈顶元素是否与当前右括号匹配。如果不匹配,字符串无效。
  5. 检查栈是否为空:遍历完字符串后,如果栈为空,说明所有的左括号都有对应的右括号,字符串有效;否则,字符串无效。

代码分析:

bool isValid(char*s)
{//定义一个栈Stack st;StackInit(&st);//初始化一个布尔变量 ret 为 true,用于记录字符串是否有效bool ret = true;// while 循环遍历字符串while (*s != '\0'){//处理左括号if (*s == '[' || *s == '(' || *s == '{'){StackPush(&st, *s);++s;//如果当前字符是左括号,将其压入栈中,并将指针 s 指向下一个字符}//处理右括号else{//先检查栈是否为空if (StackEmpty(&st))//这里为空,说明没有对应的左括号{ret = false;break;//跳出循环}//如果栈不为空,获取栈顶元素char top = StackTop(&st);//检查栈顶元素是否与当前右括号匹配//不匹配,将 ret 置为 false 并跳出循环if (*s == ']' && top != '[')//当当前字符是右中括号 ] 时,检查栈顶元素是否为左中括号 [。//如果不是,说明括号不匹配,字符串无效,将 ret 设为 false 并跳出循环。{ret = false;break;}if (*s == ')' && top != '('){ret = false;break;}if (*s == '}' && top != '{'){ret = false;break;}//匹配,弹出栈顶元素,并将指针 s 指向下一个字符StackPop(&st);++s;}}//检查栈是否为空if (*s == '\0'){ret = StackEmpty(&st);}//遍历完字符串后,如果栈为空,说明所有的左括号都有对应的右括号,将 ret 置为 true;//否则,将 ret 置为 falseStackDestory(&st);return ret;
}int main()
{//定义一个测试字符串 testchar test[] = "{[()]}";//调用 isValid 函数判断该字符串是否有效,并将结果存储在 result 中bool result= isValid(test);if (result){printf("字符串有效\n");}else{printf("字符串无效\n");}return 0;
}

问题:为什么要检查栈是否为空🤔🤔🤔

if (*s == '\0')
{ret = StackEmpty(&st);
}

原因:
在遍历完字符串后,还需要检查栈是否为空。因为如果字符串是有效的,那么所有的左括号都应该有对应的右括号与之匹配,即栈中不应该有剩余的左括号。所以使用StackEmpty(&st)来检查栈是否为空,如果栈为空,说明所有括号都匹配成功,将ret设为 true;如果栈不为空,说明还有左括号没有对应的右括号,字符串无效,将ret设为 false
综上所述,这一步是为了确保字符串中所有的左括号都有对应的右括号,避免出现多余的左括号

2.用队列实现栈

题目:在这里插入图片描述

解题思路

栈遵循后进先出(LIFO)的原则,而队列遵循先进先出(FIFO)的原则。要利用两个队列模拟栈,关键在于合理运用两个队列的入队和出队操作,以此实现栈的入栈、出栈、获取栈顶元素以及判断栈是否为空等操作。

  • 入栈操作:把新元素添加到非空的队列里。若两个队列都为,可任选一个队列添加元素。
  • 出栈操作:把非空队列里除最后一个元素之外所有元素转移到另一个空队列中,接着将最后一个元素出队,这个元素就是栈顶元素。
  • 获取栈顶元素:直接获取非空队列的队尾元素。
  • 判断栈是否为空:当两个队列都为空时,栈为空。

代码分析:

// 定义用两个队列模拟的栈结构体
typedef struct{Queue q1;Queue q2;
} MyStack;// 创建栈
MyStack* myStackCreate() 
{MyStack* st = (MyStack*)malloc(sizeof(MyStack));if (st == NULL) {printf("内存分配失败\n");exit(-1);}//调用 QueueInit 函数对 q1 和 q2 两个队列进行初始化//&st->q1 表示取 st 所指向的结构体中 q1 成员的地址QueueInit(&st->q1);QueueInit(&st->q2);return st;//回指向新创建的 MyStack 结构体的指针
}// 入栈
void myStackPush(MyStack* obj, int x)//MyStack* obj 是指向要操作的栈的指针 
{//检查 q1 队列是否为空if (!QueueEmpty(&obj->q1)) //表示 q1 队列不为空{QueuePush(&obj->q1, x);//若 q1 队列不为空,就把元素 x 入队到 q1 中}else {QueuePush(&obj->q2, x);//若 q1 队列为空,将元素 x 入队到 q2 中}
}// 出栈
int myStackPop(MyStack* obj)
{//初始化两个指针 emptyQ 和 nonemptyQ,分别指向 q1 和 q2 队列Queue* emptyQ = &obj->q1;Queue* nonemptyQ = &obj->q2;//检查 q1 队列是否为空,若不为空,交换 emptyQ 和 nonemptyQ 的指向if (!QueueEmpty(&obj->q1)) {emptyQ = &obj->q2;nonemptyQ = &obj->q1;}//当非空队列中的元素数量大于 1 时,执行循环while (QueueSize(nonemptyQ) > 1) {QueuePush(emptyQ, QueueFront(nonemptyQ));//把非空队列的队首元素入队到空队列中QueuePop(nonemptyQ);//将非空队列的队首元素出队}int top = QueueFront(nonemptyQ);//获取非空队列的队首元素,此元素即为栈顶元素QueuePop(nonemptyQ);//将栈顶元素出队return top;//返回栈顶元素
}// 获取栈顶元素
int myStackTop(MyStack* obj)
{if (!QueueEmpty(&obj->q1))//检查 q1 队列是否为空,若不为空 {return QueueBack(&obj->q1);//返回 q1 队列的队尾元素}else {return QueueBack(&obj->q2);//若 q1 队列为空,返回 q2 队列的队尾元素}
}// 判断栈是否为空
bool myStackEmpty(MyStack* obj) 
{return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);//当且仅当 q1 和 q2 两个队列都为空时,返回 true,否则返回 false
}// 销毁栈
void myStackFree(MyStack* obj)
{if (obj == NULL){return;}QueueDestroy(&obj->q1);QueueDestroy(&obj->q2);free(obj);
}
int main()
{MyStack* st = myStackCreate();if (st == NULL) {return 1;检查栈是否创建成功,若失败,返回 1 表示程序异常退出}//依次将元素 1、2、3 入栈myStackPush(st, 1);myStackPush(st, 2);myStackPush(st, 3);while (!myStackEmpty(st)){printf("栈顶元素为: %d\n", myStackTop(st));myStackPop(st);}myStackFree(st);return 0;
}

运行结果:

在这里插入图片描述

3.用栈实现队列

题目:在这里插入图片描述

在这里插入图片描述

代码分析:

typedef struct
{//两个栈Stack _pushST;//注意这里很容易错Stack _popST;//要空格表示两个成员变量是栈类型
}MyQueue;MyQueue* mQueueCreate()
{MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));StackInit(&q->_pushST);StackInit(&q->_popST);return q;
}//入栈
void myQueuePush(MyQueue* obj, int x)
{StackPush(&obj->_pushST, x);
}//出栈
int myQueuePop(MyQueue* obj)
{int front = myQueuePeek(obj);StackPop(&obj->_popST);return front;
}int myQueuePeek(MyQueue* obj)
{//如果是非空的if (!StackEmpty(&obj->_popST)){return StackTop(&obj->_popST);//返回_pushST队头的数据}//为空就要把另外一个栈里面的数据导过来else{while (!StackEmpty(&obj->_pushST)){StackPush(&obj->_popST, StackTop(&obj->_pushST));StackPop(&obj->_pushST);//将_pushST里面的数据导到_popST里面}return StackTop(&obj->_popST);}
}//判断是不是为空
//判断队列是否为空函数
bool myQueueEmpty(MyQueue* obj)
{return StackEmpty(&obj->_popST) && StackEmpty(&obj->_pushST);
}void myQueueFree(MyQueue* obj)
{StackDestory(&obj->_pushST);//调用 StackDestory 函数分别销毁 _pushST 和 _popST 栈,释放栈所占用的内存StackDestory(&obj->_popST);free(obj);//最后使用 free 函数释放 MyQueue 结构体本身所占用的内存
}//栈是后进先出;队列是先进先出
int main() 
{MyQueue* queue = mQueueCreate();// 入队操作myQueuePush(queue, 1);myQueuePush(queue, 2);myQueuePush(queue, 3);// 获取队头元素//注意:在这段用两个栈模拟队列的代码里,获取队头元素主要是从 _popST 栈获取printf("队头元素: %d\n", myQueuePeek(queue));// 出队操作printf("出队元素: %d\n", myQueuePop(queue));printf("出队元素: %d\n", myQueuePop(queue));// 再次入队myQueuePush(queue, 4);// 继续出队while (!myQueueEmpty(queue)) {printf("出队元素: %d\n", myQueuePop(queue));}// 释放队列内存myQueueFree(queue);return 0;
}

详细解析:

  1. 结构体定义
typedef struct
{//两个栈Stack _pushST; // 用于入队操作的栈Stack _popST;  // 用于出队操作的栈
}MyQueue;
  • 定义了一个名为MyQueue的结构体,该结构体包含两个Stack类型的成员变量_pushST _popST
  • _pushST 栈主要用于元素的入队操作,新元素会被压入这个栈。
  • _popST 栈用于元素的出队操作,当需要出队时,会从这个栈中弹出元素。
  1. 队列创建函数
MyQueue* mQueueCreate()
{MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));StackInit(&q->_pushST);StackInit(&q->_popST);return q;
}
  • mQueueCreate 函数的作用是创建一个新的MyQueue实例。
  • 首先使用malloc函数为MyQueue结构体分配内存空间。
  • 然后调用StackInit函数分别对_pushST_popST栈进行初始化。
  • 最后返回指向新创建的MyQueue实例的指针。
  1. 入队操作函数
//入栈
void myQueuePush(MyQueue* obj, int x)
{StackPush(&obj->_pushST, x);
}
  • myQueuePush 函数用于将一个整数x插入到队列中。
  • 直接调用StackPush函数将元素x压入_pushST栈,因为_pushST栈专门用于入队操作
  1. 出队操作函数
//出栈
int myQueuePop(MyQueue* obj)
{int front = myQueuePeek(obj);StackPop(&obj->_popST);return front;
}
  • myQueuePop 函数用于从队列中移除返回队头元素。
  • 首先调用myQueuePeek函数获取队头元素的值,并将其存储在变量front中。
  • 然后调用StackPop函数从_popST栈中弹出队头元素。
  • 最后返回队头元素的值。
  1. 获取队头元素函数
int myQueuePeek(MyQueue* obj)
{//如果是非空的if (!StackEmpty(&obj->_popST)){return StackTop(&obj->_popST); // 返回_pushST队头的数据}//为空就要把另外一个栈里面的数据导过来else{while (!StackEmpty(&obj->_pushST)){StackPush(&obj->_popST, StackTop(&obj->_pushST));StackPop(&obj->_pushST);//将_pushST里面的数据导到_popST里面}return StackTop(&obj->_popST);}
}
  • myQueuePeek 函数用于返回队列的队头元素,但不将其从队列中移除
  • 首先检查_popST栈是否为空。如果不为空,直接调用StackTop函数返回_popST栈的栈顶元素,因为 _popST 栈的栈顶元素就是队列的队头元素。
  • 如果_popST为空,则需要将_pushST栈中的所有元素依次弹出并压入_popST栈中,这样 _popST 栈中的元素顺序就与队列的顺序一致了。
  • 最后返回_popST栈的栈顶元素。

代码运行:

在这里插入图片描述

4.设计循环队列

题目:在这里插入图片描述

画图分析:
在这里插入图片描述

代码分析:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef struct
{int* _a;//是一个整数指针,用于指向存储队列元素的动态数组int _front;//表示队列的队头位置int _rear;//表示队列的队尾位置int _k;//表示队列的最大容量
}MyCircularQueue;//初始化
MyCircularQueue* myCircularQueueCreate(int k)
{MyCircularQueue* q = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//为 MyCircularQueue 结构体分配内存q->_a = (int*)malloc(sizeof(int) * (k + 1));//多开一个空间//为存储队列元素的数组分配 k + 1 个整数的空间,多开一个空间是为了区分队列满和队列空的情况q->_front = 0;q->_rear = 0;q->_k = k;//记录队列的最大容量 kreturn q;
}//空的
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{return obj->_front == obj->_rear;//当 _front 和 _rear 相等时,队列为空
}//满的
bool myCircularQueueIsFull(MyCircularQueue* obj)
{return (obj->_rear + 1) % (obj->_k + 1) == obj->_front;
}//插入数据
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{//如果是满的if (myCircularQueueIsFull(obj)){return false;}//入数据obj->_a[obj->_rear] = value;//将元素插入到队尾位置obj->_rear++;obj->_rear %= (obj->_k  + 1);//更新 _rear 的位置,使用取模运算实现循环return true;
}//删除数据
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{//为空if (myCircularQueueIsEmpty(obj)){return false;}++obj->_front;obj->_front %= (obj->_k + 1);return true;
}//获取队头的数据
int myCircularQueueFront(MyCircularQueue* obj)
{//如果是空的if(myCircularQueueIsEmpty(obj)){return -1;}else{return obj->_a[obj->_front];//返回队头元素}
}//获取队尾的数据
int myCircularQueueRear(MyCircularQueue* obj)
{//如果是空的if (myCircularQueueIsEmpty(obj)){return -1;}else{int tail = obj->_rear - 1;//计算队尾元素的位置,考虑循环的情况if (tail == -1){tail = obj->_k;}return obj->_a[tail];//返回队尾元素}
}//释放
void myCircularQueueFree(MyCircularQueue* obj)
{free(obj->_a);free(obj);
}int main() 
{MyCircularQueue* queue = myCircularQueueCreate(3);myCircularQueueEnQueue(queue, 1);myCircularQueueEnQueue(queue, 2);myCircularQueueEnQueue(queue, 3);printf("Front: %d\n", myCircularQueueFront(queue));//打印队头printf("Rear: %d\n", myCircularQueueRear(queue));//打印队尾myCircularQueueDeQueue(queue);//队头元素 1 出队printf("Front after dequeue: %d\n", myCircularQueueFront(queue));//那就2变成了队头myCircularQueueFree(queue);return 0;
}

运行结果:

在这里插入图片描述

🤔🤔🤔思考一个问题
这里是怎么使用取模运算实现循环的

入队操作中的取模运算

// 插入数据
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{// 如果是满的if (myCircularQueueIsFull(obj)){return false;}// 入数据obj->_a[obj->_rear] = value;obj->_rear++;obj->_rear %= (obj->_k + 1);return true;
}
  1. 元素入队:obj->_a[obj->_rear] = value; 把新元素value存到_rear所指向的位置。
  2. 移动队尾指针:obj->_rear++; _rear指针向后移动一位。
  3. 取模运算实现循环:obj->_rear %= (obj->_k + 1); _rear进行取模运算,其除数为 _k + 1(_k 代表队列的最大容量)。

示例说明:

  • 假设队列的最大容量_k 3,那么数组的大小就是 _k + 1 = 4,数组下标范围是0 3
  • 初始时,_rear = 0,插入元素后,_rear 变为 1
  • 持续插入元素,当_rear变为3时,再插入元素,_rear 先加1变成 4,然后进行取模运算 4 % 4 = 0,这就使得_rear又回到了数组的起始位置,达成了循环的效果。

出队操作中的取模运算

// 删除数据
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{// 为空if (myCircularQueueIsEmpty(obj)){return false;}++obj->_front;obj->_front %= (obj->_k + 1);return true;
}
  1. 移动队头指针:++obj->_front; _front 指针向后移动一位。
  2. 取模运算实现循环:obj->_front %= (obj->_k + 1); 对 _front 进行取模运算,除数同样是 _k + 1

示例说明:

  • 同样假设队列的最大容量 _k 为 3,数组大小为 4,下标范围是0 3
  • 初始时,_front = 0,出队操作后,_front 变为 1
  • 不断进行出队操作,当_front变为3时,再出队,_front 先加1变成 4,接着进行取模运算 4 % 4 = 0_front 又回到了数组的起始位置,实现了循环

总结:在循环队列中,取模运算能够把指针的移动范围限制在数组的有效下标范围之内,当指针移动到数组末尾时,通过取模运算可以让指针回到数组的起始位置,从而实现循环的效果。这样就能高效地利用数组空间,避免 “假溢出” 问题。

🎉🎉🎉
在这里本章就结束啦~
我们下期见~

在这里插入图片描述

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

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

相关文章

精益数据分析(8/126):从Airbnb案例看精益创业与数据驱动增长

精益数据分析&#xff08;8/126&#xff09;&#xff1a;从Airbnb案例看精益创业与数据驱动增长 大家好&#xff01;一直以来&#xff0c;我都坚信在创业和技术的领域里&#xff0c;持续学习与分享是不断进步的关键。今天&#xff0c;咱们继续深入学习《精益数据分析》&#x…

专题二十:路由策略与策略路由

一、路由策略 1.1 路由策略的概念 路由策略是通过修改路由表的路由条目来控制数据流量的可达性。即对接受和发布的路由进过滤。这种方式称为路由策略 路由策略功能相关作用控制路由的发布可通过路由策略对所要发布的路由信息进行过滤&#xff0c;只允许发布满足条件的路由信…

VSCode 扩展离线下载方法

学习自该文章&#xff0c;感谢作者&#xff01; 2025 年 VSCode 插件离线下载攻略&#xff1a;官方渠道一键获取 - 知乎 获取扩展关键信息 方法一&#xff1a;官网获取 打开 VSCode 扩展官方网站 搜索要下载的扩展&#xff0c;以 CodeGeeX 为例&#xff0c;网址为&#xf…

一 、环境的安装 Anaconda + Pycharm + PaddlePaddle

《从零到一实践&#xff1a;系统性学习生成式 AI(NLP)》 一 、环境的安装 Anaconda Pycharm PaddlePaddle 1. Anaconda 软件安装 Anaconda 软件安装有大量的教程&#xff0c;此处不在说明&#xff0c;安装完成之后界面如下&#xff1a; 2. 创建 Anaconda 虚拟环境 Paddl…

软考教材重点内容 信息安全工程师 第23章 云计算安全需求分析与安全保护工程

23.1.云计算基本概念 云计算就是在这样的需求驱动下而产生的一种计算模式。云计算通过虚拟化及网络通信技术&#xff0c;提供一种按需服务、弹性化的 IT 资源池服务平台。云计算的主要特征如下。 1. IT 资源以服务的形式提供 IT 资源以一种服务产品的形式提供&#xff0c;满…

蓝桥杯 19. 最大比例

最大比例 原题目链接 题目描述 X 星球的某个大奖赛设了 M 级奖励。每个级别的奖金是一个正整数。 并且&#xff0c;相邻两个级别间的比例是一个固定值&#xff0c;也就是说&#xff1a;所有级别的奖金构成一个等比数列。 例如&#xff1a; 奖金数列为 16, 24, 36, 54&…

基于 Python 的自然语言处理系列(82):Transformer Reinforcement Learning

&#x1f517; 本文所用工具&#xff1a;trl、transformers、peft、bitsandbytes &#x1f4d8; 官方文档参考&#xff1a;https://huggingface.co/docs/trl 一、引言&#xff1a;从有监督微调到 RLHF 全流程 随着语言大模型的发展&#xff0c;如何在大规模预训练模型基础上更精…

JAVA猜数小游戏

import java.util.Random; import java.util.Scanner;public class HelloWorld {public static void main(String[] args) {Random rnew Random();int luck_number r.nextInt(100)1;while (true){System.out.println("输入猜数字");Scanner sc new Scanner(System…

GPU渲染阶段介绍+Shader基础结构实现

GPU是什么 &#xff08;CPU&#xff09;Center Processing Unit:逻辑编程 &#xff08;GPU&#xff09;Graphics Processing Unit&#xff1a;图形处理&#xff08;矩阵运算&#xff0c;数据公式运算&#xff0c;光栅化&#xff09; 渲染管线 渲染管线也称为渲染流水线&#x…

Spring Boot + MyBatis 动态字段更新方法

在Spring Boot和MyBatis中&#xff0c;实现动态更新不固定字段的步骤如下&#xff1a; 方法一&#xff1a;使用MyBatis动态SQL&#xff08;适合字段允许为null的场景&#xff09; 定义实体类 包含所有可能被更新的字段。 Mapper接口 定义更新方法&#xff0c;参数为实体对象&…

单例模式:确保唯一实例的设计模式

单例模式&#xff1a;确保唯一实例的设计模式 一、模式核心&#xff1a;保证类仅有一个实例并提供全局访问点 在软件开发中&#xff0c;有些类需要确保只有一个实例&#xff08;如系统配置类、日志管理器&#xff09;&#xff0c;避免因多个实例导致状态混乱或资源浪费。 单…

UnoCSS原子CSS引擎-前端福音

UnoCSS是一款原子化的即时按需 CSS 引擎&#xff0c;其中没有核心实用程序&#xff0c;所有功能都是通过预设提供的。默认情况下UnoCSS应用通过预设来实现相关功能。 UnoCSS中文文档&#xff1a; https://www.unocss.com.cn 前有很多种原子化的框架&#xff0c;例如 Tailwind…

【Qwen2.5-VL 踩坑记录】本地 + 海外账号和国内账号的 API 调用区别(阿里云百炼平台)

API 调用 阿里云百炼平台的海内外 API 的区别&#xff1a; 海外版&#xff1a;需要进行 API 基础 URL 设置国内版&#xff1a;无需设置。 本人的服务器在香港&#xff0c;采用海外版的 API 时&#xff0c;需要进行如下API端点配置 / API基础URL设置 / API客户端配置&#xf…

C语言笔记(鹏哥)上课板书+课件汇总(结构体)-----数据结构常用

结构体 目录&#xff1a; 1、结构体类型声明 2、结构体变量的创建和初始化 3、结构体成员访问操作符 4、结构体内存对齐*****&#xff08;重要指数五颗星&#xff09; 5、结构体传参 6、结构体实现位段 一、结构体类型声明 其实在指针中我们已经讲解了一些结构体内容了&…

UV: Python包和项目管理器(从入门到不放弃教程)

目录 UV: Python包和项目管理器&#xff08;从入门到不放弃教程&#xff09;1. 为什么用uv&#xff0c;而不是conda或者pip2. 安装uv&#xff08;Windows&#xff09;2.1 powershell下载2.2 winget下载2.3 直接下载安装包 3. uv教程3.1 创建虚拟环境 (uv venv) 4. uvx5. 此pip非…

网络开发基础(游戏方向)之 概念名词

前言 1、一款网络游戏分为客户端和服务端两个部分&#xff0c;客户端程序运行在用户的电脑或手机上&#xff0c;服务端程序运行在游戏运营商的服务器上。 2、客户端和服务端之间&#xff0c;服务端和服务端之间一般都是使用TCP网络通信。客户端和客户端之间通过服务端的消息转…

java将pdf转换成word

1、jar包准备 在项目中新增lib目录&#xff0c;并将如下两个文件放入lib目录下 aspose-words-15.8.0-jdk16.jar aspose-pdf-22.9.jar 2、pom.xml配置 <dependency><groupId>com.aspose</groupId><artifactId>aspose-pdf</artifactId><versi…

【C/C++】插件机制:基于工厂函数的动态插件加载

本文介绍了如何通过 C 的 工厂函数、动态库&#xff08;.so 文件&#xff09;和 dlopen / dlsym 实现插件机制。这个机制允许程序在运行时动态加载和调用插件&#xff0c;而无需在编译时知道插件的具体类型。 一、 动态插件机制 在现代 C 中&#xff0c;插件机制广泛应用于需要…

【音视频】AAC-ADTS分析

AAC-ADTS 格式分析 AAC⾳频格式&#xff1a;Advanced Audio Coding(⾼级⾳频解码)&#xff0c;是⼀种由MPEG-4标准定义的有损⾳频压缩格式&#xff0c;由Fraunhofer发展&#xff0c;Dolby, Sony和AT&T是主 要的贡献者。 ADIF&#xff1a;Audio Data Interchange Format ⾳…

机器学习 Day12 集成学习简单介绍

1.集成学习概述 1.1. 什么是集成学习 集成学习是一种通过组合多个模型来提高预测性能的机器学习方法。它类似于&#xff1a; 超级个体 vs 弱者联盟 单个复杂模型(如9次多项式函数)可能能力过强但容易过拟合 组合多个简单模型(如一堆1次函数)可以增强能力而不易过拟合 集成…