【数据结构】栈和队列-----数据结构中的双生花

文章目录

    • @[toc]
  • 栈与队列:数据结构中的双生花
    • 1. 栈:后进先出的有序世界
      • 1.1 概念及结构剖析
      • 1.2 实现方式深度解析
        • 数组 vs 链表实现
      • 1.3 动态栈实现详解(附程序源码)
        • 1.定义一个动态栈
        • 2.初始化
        • 3.销毁
        • 4.入栈
        • 5.出栈
        • 6.取栈顶数据
        • 7.判空
        • 8.获取数据个数
        • 9.访问栈
        • 10.程序源码
      • 1.4 栈的应用场景
        • 1. 函数调用栈
        • 2. 表达式求值
        • 3. 浏览器历史记录
        • 4. 撤销操作(Undo)
    • 2. 队列:先进先出的公平之师
      • 2.1 概念及结构剖析
      • 2.2 实现方式
        • 为什么链表实现更优?
      • 2.3 队列实现详解(附程序源码)
        • 核心数据结构定义
        • 1.初始化
        • 2.队列的销毁
        • 3.队尾插入
        • 4.队头删除
        • 5.统计队列中数据个数
        • 6.取队头数据
        • 7.取队尾数据
        • 8.判空
        • 9.访问队列
        • 10.程序源码
      • 2.4 队列的应用场景
        • 1. 消息队列系统
        • 2. 打印机任务调度
        • 3. 广度优先搜索(BFS)
        • 4. CPU任务调度
    • 3. 栈与队列的对比分析
    • 4. 高级变体与应用
      • 4.1 双端队列(Deque)
      • 4.2 优先队列(Priority Queue)
    • 5. 总结:选择合适的数据结构

在这里插入图片描述

栈与队列:数据结构中的双生花

在计算机科学的世界里,栈和队列如同双生花般存在——它们看似相似却各有千秋,共同构成了最基本也是最强大的数据结构工具集。

1. 栈:后进先出的有序世界

1.1 概念及结构剖析

栈(Stack)是一种特殊的线性表,其核心特性是只允许在固定一端(栈顶)进行插入和删除操作。这种结构遵循**后进先出(LIFO)**原则:最后进入的元素最先被移除。

关键术语解析

  • 压栈/入栈(Push):在栈顶插入新元素
  • 出栈(Pop):从栈顶删除元素
  • 栈顶(Top):唯一允许操作的一端
  • 栈底(Bottom):不允许操作的一端

结构可视化

栈顶 → D → C → B → A ← 栈底
出栈顺序:D → C → B → A

在这里插入图片描述

在这里插入图片描述

1.2 实现方式深度解析

数组 vs 链表实现

在栈的实现中,数组和链表各有优劣:

特性数组实现链表实现
内存使用连续内存空间非连续内存空间
扩容成本较高(需重新分配)较低(动态分配)
访问速度O(1) 随机访问O(n) 顺序访问
缓存友好性
实现复杂度简单中等

为什么数组实现更优?
对于栈这种主要在尾部操作的数据结构,数组的尾部插入/删除操作时间复杂度为O(1),且CPU缓存预取机制对连续内存访问更友好。虽然扩容时需要重新分配内存,但通过倍增策略可以摊还这一成本。

在这里插入图片描述

在这里插入图片描述

1.3 动态栈实现详解(附程序源码)

跟链表一样,我们采用多文件操作

在这里插入图片描述

1.定义一个动态栈
typedef int STDataType;
typedef struct Stack {STDataType* _a;     // 动态数组int _top;           // 栈顶位置int _capacity;      // 容量
} ST;
2.初始化
void STInit(ST* pst)
{assert(pst);pst->a = 0;pst->capacity = 0;pst->top = 0;
}

在这有两种写法,第一种是top指向栈顶,第二种是top指向栈顶的下一个位置

我个人更推荐第二种写法 这种写法的top类似于链表中的size在这里插入图片描述


3.销毁
void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}
4.入栈
void STPush(ST* pst, STDataType x)
{assert(pst);//扩容if (pst->top == pst->capacity){int newcapcacity =pst->capacity==0 ? 4 : pst->capacity * 2;//起始空间为0则申请4个空间 不为0则二倍STDataType* tmp = (STDataType*)ralloc(pst->a, newcapcacity * sizeof(STDataType));//pst->a为NULL时,realloc相当与mallocif (tmp == NULL){perror("realloc fail");}pst->a = tmp;pst->capacity = newcapcacity;}pst->a[pst->top] = x;pst->top++;//top指向栈顶下一个元素}
5.出栈
void STPop(ST* pst)
{assert(pst);pst->top--;
}
6.取栈顶数据
STDataType STTop(ST* pst)
{assert(pst);assert(pst->top > 0);//top大于0才能取return pst->a[pst->top - 1];//top是栈顶的下一个数据 所以要-1
}
7.判空
bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;//==0就是空
}
8.获取数据个数
int STSize(ST* pst)
{assert(pst);return pst->top;//也就是获取top 因为这里的top相当于size
}
9.访问栈
#define _CRT_SECURE_NO_WARNINGS
#include"Stack.h"
int main()
{ST s;STInit(&s);STPush(&s, 1);STPush(&s, 2);STPush(&s, 3);STPush(&s, 4);while (!STEmpty(&s)){printf("%d ", STTop(&s));STPop(&s);//打印一删除一个}STDestroy(&s);return 0;
}
10.程序源码

Stack.h ———函数声明

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int STDataType;typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
//初始化和销毁
void STInit(ST* pst);
void STDestroy(ST* pst);//入栈出栈
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);//取栈顶数据
STDataType STTop(ST* pst);//判空
bool STEmpty(ST* pst);
//获取数据个数
int STSize(ST* pst);

Stack.c———函数的实现

#define _CRT_SECURE_NO_WARNINGS
#include"Stack.h"
//初始化和销毁
void STInit(ST* pst)
{assert(pst);pst->a = 0;pst->capacity = 0;pst->top = 0;
}
void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}//入栈出栈
void STPush(ST* pst, STDataType x)
{assert(pst);//扩容if (pst->top == pst->capacity){int newcapcacity =pst->capacity==0 ? 4 : pst->capacity * 2;//起始空间为0则申请4个空间 不为0则二倍STDataType* tmp = (STDataType*)realloc(pst->a, newcapcacity * sizeof(STDataType));//pst->a为NULL时,realloc相当与mallocif (tmp == NULL){perror("realloc fail");}pst->a = tmp;pst->capacity = newcapcacity;}pst->a[pst->top] = x;pst->top++;//top指向栈顶下一个元素}
void STPop(ST* pst)
{assert(pst);pst->top--;
}//取栈顶数据
STDataType STTop(ST* pst)
{assert(pst);assert(pst->top > 0);return pst->a[pst->top - 1];
}//判空
bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;//==0就是空
}
//获取数据个数
int STSize(ST* pst)
{assert(pst);return pst->top;
}

test.c——测试

#define _CRT_SECURE_NO_WARNINGS
#include"Stack.h"
int main()
{ST s;STInit(&s);STPush(&s, 1);STPush(&s, 2);STPush(&s, 3);STPush(&s, 4);while (!STEmpty(&s)){printf("%d ", STTop(&s));STPop(&s);}STDestroy(&s);return 0;
}

1.4 栈的应用场景

1. 函数调用栈

程序执行时,每次函数调用都会在栈中创建一个栈帧(Stack Frame),存储:

  • 返回地址

  • 局部变量

  • 函数参数

  • 寄存器状态

    void funcA() {int a = 10; // 栈帧创建funcB();// 返回后栈帧销毁
    }void funcB() {int b = 20; // 新栈帧
    }
    
    2. 表达式求值

    栈用于处理各种表达式:

    • 中缀转后缀:操作数栈和运算符栈
    • 括号匹配:遇到左括号入栈,右括号出栈
    • 计算后缀表达式:操作数入栈,遇到运算符出栈计算

    示例:(1 + 2) * 3的后缀表达式 1 2 + 3 *

    3. 浏览器历史记录

    浏览器的后退功能使用栈实现:

    class BrowserHistory:def __init__(self):self.back_stack = []   # 后退栈self.forward_stack = [] # 前进栈def visit(self, url):self.back_stack.append(url)self.forward_stack = []  # 清空前进栈def back(self):if len(self.back_stack) > 1:self.forward_stack.append(self.back_stack.pop())return self.back_stack[-1]
    
    4. 撤销操作(Undo)

    文本编辑器中的撤销机制:

    public class TextEditor {private StringBuilder text = new StringBuilder();private Stack<String> history = new Stack<>();public void type(String words) {history.push(text.toString()); // 保存状态text.append(words);}public void undo() {if (!history.isEmpty()) {text = new StringBuilder(history.pop());}}
    }
    

2. 队列:先进先出的公平之师

2.1 概念及结构剖析

队列(Queue)是一种只允许在一端(队尾)插入,在另一端(队头)删除的线性表。这种结构遵循**先进先出(FIFO)**原则:最先进入的元素最先被移除。

关键术语解析

  • 入队(Enqueue):在队尾插入新元素
  • 出队(Dequeue):从队头删除元素
  • 队头(Front):删除操作端
  • 队尾(Rear):插入操作端

结构可视化

在这里插入图片描述

队头 → A → B → C → D → E ← 队尾
出队顺序:A → B → C → D → E

2.2 实现方式

在这里插入图片描述

实现方案:队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

为什么链表实现更优?

对于队列这种需要在两端操作的数据结构:

  • 数组实现问题
    • 出队操作需要移动所有元素(O(n)时间复杂度)
    • 假溢出问题(实际空间可用但无法入队)
    • 需要复杂的环形缓冲区处理
  • 链表实现优势
    • O(1)时间复杂度的入队/出队操作
    • 动态内存分配,无固定大小限制
    • 自然避免假溢出问题

2.3 队列实现详解(附程序源码)

核心数据结构定义
typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;// 队列结构
typedef struct Queue {QNode* phead;  // 队头指针QNode* ptail;   // 队尾指针int size;//用来计数
} Queue;//用一个结构题体来放头节点跟尾节点,这样传参就可以只传一个
1.初始化
void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}
2.队列的销毁
void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}
3.队尾插入
void QueuePush(Queue* pq, QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->next = NULL;newnode->val = x;if (pq->ptail == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}
4.队头删除
void QueuePop(Queue* pq)
{assert(pq);assert(pq->phead);if (pq->phead->next == NULL)//一个节点{free(pq->phead);pq->phead = pq->ptail = NULL;}else//多个节点{QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}pq->size--;
}
5.统计队列中数据个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}
6.取队头数据
QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}
7.取队尾数据
QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->phead);return pq->ptail->val;
}
8.判空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}
9.访问队列
int main()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);while (!QueueEmpty(&q)){printf("%d ", QueueFront(&q));//取队头数据QueuePop(&q);}printf("\n");return 0;
}
10.程序源码

Queue.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;//初始化
void QueueInit(Queue* pq);
//队列的销毁
void QueueDestroy(Queue* pq);
//队尾插入
void QueuePush(Queue* pq, QDataType x);
//队头删除
void QueuePop(Queue* pq);
//统计队列中数据的个数
int QueueSize(Queue* pq);
//取队头数据
QDataType QueueFront(Queue* pq);
//取队尾数据
QDataType QueueBack(Queue* pq);//判空
bool QueueEmpty(Queue* pq);

Queue.c

#define _CRT_SECURE_NO_WARNINGS
#include"Queue.h"void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->next = NULL;newnode->val = x;if (pq->ptail == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}void QueuePop(Queue* pq)
{assert(pq);assert(pq->phead);if (pq->phead->next == NULL)//一个节点{free(pq->phead);pq->phead = pq->ptail = NULL;}else//多个节点{QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}pq->size--;
}
QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}
QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->phead);return pq->ptail->val;
}
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}
void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}

test.c

#define _CRT_SECURE_NO_WARNINGS
#include"Queue.h"
int main()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);while (!QueueEmpty(&q)){printf("%d ", QueueFront(&q));//取队头数据QueuePop(&q);}printf("\n");return 0;
}

2.4 队列的应用场景

1. 消息队列系统

现代分布式系统的核心组件:

public class MessageQueue {private Queue<Message> queue = new LinkedList<>();public synchronized void enqueue(Message msg) {queue.add(msg);notifyAll(); // 唤醒等待的消费者}public synchronized Message dequeue() throws InterruptedException {while (queue.isEmpty()) {wait(); // 等待消息到达}return queue.remove();}
}
2. 打印机任务调度

多任务打印的公平处理:

class Printer:def __init__(self):self.print_queue = deque()self.current_task = Nonedef add_document(self, document):self.print_queue.append(document)print(f"Added document: {document}")def print_next(self):if self.print_queue:self.current_task = self.print_queue.popleft()print(f"Printing: {self.current_task}")else:print("No documents to print")
3. 广度优先搜索(BFS)

图遍历算法核心:

void BFS(Graph* graph, int start) {bool visited[MAX_VERTICES] = {false};Queue queue;QueueInit(&queue);visited[start] = true;QueuePush(&queue, start);while (!QueueEmpty(&queue)) {int current = QueueFront(&queue);QueuePop(&queue);printf("Visited %d\n", current);// 遍历所有邻接节点for (int i = 0; i < graph->vertices; i++) {if (graph->adjMatrix[current][i] && !visited[i]) {visited[i] = true;QueuePush(&queue, i);}}}
}
4. CPU任务调度

操作系统核心调度算法:

struct Task {int pid;int priority;// 其他任务信息
};void scheduleTasks(Queue* highPriority, Queue* normalQueue) {while (!QueueEmpty(highPriority) || !QueueEmpty(normalQueue)) {Task* task;// 优先处理高优先级队列if (!QueueEmpty(highPriority)) {task = QueueFront(highPriority);QueuePop(highPriority);} else {task = QueueFront(normalQueue);QueuePop(normalQueue);}executeTask(task);// 任务未完成则重新入队if (!task->completed) {if (task->priority == HIGH) {QueuePush(highPriority, task);} else {QueuePush(normalQueue, task);}}}
}

3. 栈与队列的对比分析

特性栈 (Stack)队列 (Queue)
操作原则LIFO (后进先出)FIFO (先进先出)
插入位置栈顶 (Top)队尾 (Rear)
删除位置栈顶 (Top)队头 (Front)
典型操作Push, PopEnqueue, Dequeue
实现方式数组(更优)/链表链表(更优)/循环数组
空间复杂度O(n)O(n)
时间复杂度Push/Pop: O(1)Enqueue/Dequeue: O(1)
应用场景函数调用、表达式求值、回溯消息传递、BFS、缓冲、调度
抽象层次递归结构管道结构

4. 高级变体与应用

4.1 双端队列(Deque)

双端队列结合了栈和队列的特性,允许在两端进行插入和删除操作:

typedef struct DequeNode {int data;struct DequeNode* prev;struct DequeNode* next;
} DequeNode;typedef struct {DequeNode* front;DequeNode* rear;
} Deque;// 前端插入
void insertFront(Deque* dq, int data) {DequeNode* newNode = createNode(data);if (dq->front == NULL) {dq->front = dq->rear = newNode;} else {newNode->next = dq->front;dq->front->prev = newNode;dq->front = newNode;}
}// 后端删除
int deleteRear(Deque* dq) {if (dq->rear == NULL) return -1; // 错误值DequeNode* temp = dq->rear;int data = temp->data;if (dq->front == dq->rear) {dq->front = dq->rear = NULL;} else {dq->rear = dq->rear->prev;dq->rear->next = NULL;}free(temp);return data;
}

4.2 优先队列(Priority Queue)

优先队列是队列的变体,元素按优先级出队:

typedef struct {int* heap;       // 堆数组int capacity;    // 最大容量int size;        // 当前大小
} PriorityQueue;void enqueue(PriorityQueue* pq, int value) {if (pq->size == pq->capacity) {// 扩容逻辑}// 将新元素添加到堆尾int i = pq->size++;pq->heap[i] = value;// 上滤操作while (i != 0 && pq->heap[(i-1)/2] > pq->heap[i]) {swap(&pq->heap[i], &pq->heap[(i-1)/2]);i = (i-1)/2;}
}int dequeue(PriorityQueue* pq) {if (pq->size <= 0) return INT_MIN;int root = pq->heap[0];pq->heap[0] = pq->heap[--pq->size];// 下滤操作int i = 0;while (true) {int smallest = i;int left = 2*i + 1;int right = 2*i + 2;if (left < pq->size && pq->heap[left] < pq->heap[smallest])smallest = left;if (right < pq->size && pq->heap[right] < pq->heap[smallest])smallest = right;if (smallest != i) {swap(&pq->heap[i], &pq->heap[smallest]);i = smallest;} else {break;}}return root;
}

5. 总结:选择合适的数据结构

栈和队列作为基础数据结构,在算法设计和系统开发中无处不在:

  1. 选择栈的场景
    • 需要回溯操作(如撤销功能)
    • 递归算法实现
    • 深度优先搜索(DFS)
    • 语法解析和表达式求值
  2. 选择队列的场景
    • 需要公平处理(如任务调度)
    • 广度优先搜索(BFS)
    • 缓冲区和数据传输
    • 消息传递系统
  3. 混合使用场景
    • 使用队列实现栈(需要两个队列)
    • 使用栈实现队列(需要两个栈)
    • 双端队列满足双向操作需求
    • 优先队列处理带优先级的任务

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

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

相关文章

Mybatis-2快速入门

学习主线 必学必会属于优化的东西。 快速入门需求说明 要求&#xff1a;开发一个MyBatis项目&#xff0c;通过MyBatis的方式可以完成对monster表的crud操作 1.创建mybatis数据库-monster表 主键Primary Key默认非空Not null&#xff0c;就省略了 create database mybatis us…

Web基础 -java操作数据库

一、JDBCJDBC&#xff1a;&#xff08;Java DataBase Connectivity&#xff09;&#xff0c;就是使用Java语言操作关系型数据库的一套API。为了使用JDBC操作数据库&#xff0c;首先&#xff0c;我们需要在pom.xml文件中引入依赖<dependencies><!-- MySQL JDBC driver …

cell2location复现

https://github.com/BayraktarLab/cell2location/issues/348 根据你已下载的本地 wheel 文件&#xff0c;可以通过以下方式修改安装命令&#xff0c;优先从本地路径安装 jaxlib&#xff0c;同时保持其他依赖的安装方式不变&#xff1a; 解决方案 # 安装 jax (从远程 PyPI 源) p…

什么是 npm、Yarn、pnpm? 有什么区别? 分别适应什么场景?

什么是 npm、Yarn、pnpm? 有什么区别? 分别适应什么场景? 在前端开发中&#xff0c;包管理工具扮演着非常重要的角色。它们帮助开发者高效地管理项目的依赖&#xff0c;确保项目中所需的所有第三方库和工具都能按时安装&#xff0c;并且兼容版本。npm、Yarn 和 pnpm 是三款…

深度隐匿源IP:高防+群联AI云防护防绕过实战

隐蔽性挑战 黑客常通过以下手段绕过基础防护&#xff1a; HTTPS证书嗅探&#xff1a;访问 https://源站IP&#xff0c;通过证书域名匹配暴露真实IP历史解析记录追踪&#xff1a;从DNS数据库获取旧A记录CDN缓存渗透&#xff1a;利用边缘节点回源漏洞定位源站 三重防护方案 高防I…

如何加快golang编译速度

跟着我的步骤来&#xff1a;第一步&#xff1a;(点击edit)第二步&#xff1a;将go tool arguments设置为-p4&#xff0c;初始值设为4&#xff0c; 代表最多同时编译4个包&#xff08;非文件&#xff09;。电脑性能好时&#xff0c;可设为CPU最大核心数&#xff08;充分利用多核…

浏览器自动化方案

B端后台列表页自动新增素材方案 我设计了一套完整的浏览器自动化方案&#xff0c;使用 Puppeteer 实现B端后台列表页的自动新增素材功能。该方案包含数据组织、浏览器操作、错误处理等完整流程。 一、技术选型 浏览器自动化工具&#xff1a;Puppeteer (https://pptr.dev)任务调…

MPPT电路设计

反激的具体计算过程要写好起码要一天&#xff0c;所以本次先更MPPT。这章不计算具体参数&#xff0c;只做分析。 目录 一、电路作用 二、电路设计 采样电路和输入电路 主体电路 驱动电路 一、电路作用 MPPT电路是一种广泛应用于光伏发电、风力发电等新能源系统中的关键电…

【基于飞浆训练车牌识别模型】

基于飞浆训练车牌识别模型 基于飞浆训练车牌识别模型 LPRNet&#xff08;License Plate Recognition via Deep Neural Networks&#xff09;是一种轻量级卷积神经网络&#xff0c;专为端到端车牌识别设计&#xff0c;由Intel IOTG Computer Vision Group的Sergey Zherzdev于201…

No module named ‘sklearn‘

1、运行python数据分析库时报错 No module named sklearn2、原因 虚拟环境未安装 sklearn 库&#xff08;即 scikit-learn&#xff09;。 3、解决方案 pip install scikit-learn使用国内镜像源&#xff1a; pip install scikit-learn -i https://mirrors.aliyun.com/pypi/simpl…

XPath注入攻击详解:原理、危害与防御

什么是XPath注入&#xff1f; XPath注入&#xff08;XPath Injection&#xff09;是一种针对使用XPath查询语言的应用程序的安全攻击技术&#xff0c;类似于SQL注入。当应用程序使用用户提供的输入来构造XPath查询而没有进行适当的过滤或转义时&#xff0c;攻击者可以通过构造恶…

网络编程(套接字)

目录 一、套接字 1、套接字的作用 2、关于TCP和UDP协议 1. TCP协议 2. UDP协议 3. 两者的区别 2、套接字函数 1&#xff09;函数 socket&#xff08;创建套接字同文件描述符&#xff09; 2&#xff09;准备套接字用结构体 1. 套接字的结构体 2. 客户端的套接字&…

R语言安装包

# 在安装过程中指定源地址 install.packages("RCurl", repos "https://mirrors.tuna.tsinghua.edu.cn/CRAN/") # 查看当前镜像 options()$repos # 设置为中科大镜像 options("repos" c(CRAN"https://mirrors.ustc.edu.cn/CRAN/")…

微服务引擎 MSE 及云原生 API 网关 2025 年 5 月产品动态

点击此处&#xff0c;了解微服务引擎 MSE 产品详情。

性能测试过程中监控linux服务器资源情况

文章目录1. cpu使用情况&#xff08;1&#xff09;性能瓶颈类型CPU密集型瓶颈​​I/O或等待瓶颈​&#xff08;2&#xff09;资源分配与竞争​资源争用分析​虚拟化环境资源分配​&#xff08;3&#xff09;系统稳定性与异常​​异常波动与毛刺​​过热降频影响​&#xff08;4…

使用defineExpose暴露子组件的属性和方法、页面生命周期onLoad和onReady的使用

欢迎来到我的UniApp技术专栏&#xff01;&#x1f389; 在这里&#xff0c;我将与大家分享关于UniApp开发的实用技巧、最佳实践和项目经验。 专栏特色&#xff1a; &#x1f4f1; 跨平台开发一站式解决方案 &#x1f680; 从入门到精通的完整学习路径 &#x1f4a1; 实战项目经…

新手必看!VSCodePyCharm 配置 OpenCV 超详细教程(支持 Python 和 C++ 双语言)

新手必看&#xff01;VSCode&PyCharm 配置 OpenCV 超详细教程&#xff08;支持 Python 和 C 双语言&#xff09; 适用对象&#xff1a;初学者&#xff0c;希望在 VSCode 与 PyCharm 两款常用 IDE 中&#xff0c;学会配置并使用 OpenCV&#xff0c;分别实现 Python 与 C 环境…

PyTorch深度学习框架入门案例实战

PyTorch深度学习框架详解与实战 1. PyTorch简介与环境配置 1.1 安装与导入 # 基础导入 import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset import numpy as np import…

Spring Boot - Spring Boot 集成 MyBatis 分页实现 手写 SQL 分页

一、准备阶段 1、依赖引入 pom.xml <properties>...<postgresql.verison>42.5.6</postgresql.verison><mybatis.version>3.0.1</mybatis.version> </properties><dependencies>...<!-- postgresql 驱动 --><dependency>…

李宏毅《生成式人工智能导论》 | 第9讲 AI Agent

文章目录大模型未来趋势&#xff1a;以大型语言模型打造的AgentAI Agent运行的可能原理有记忆的ChatGPT大模型未来趋势&#xff1a;以大型语言模型打造的Agent 人类需要做多步骤的复杂任务&#xff0c;AI可以做到这件事吗&#xff1f; 如果可以我们将其称为AI Agent&#xff…