2025届视觉算法开发工程师面试问题汇总

news/2025/1/11 14:48:40/

2025届视觉算法开发工程师面试问题汇总

  • 1. 数据结构
    • 1.1 时间复杂度
  • 2. 算法问题
    • 2.1 两数之和
    • 2.2 递归求二叉树的深度
    • 2.3 一个由0和1组成数组中,计算出这里面连续1的最大数
  • 3. C++、Python、Cuda问题
    • 3.1 C++
      • 3.1.1 智能指针
        • 3.1.1.1 std::unique_ptr独占指针
        • 3.1.1.2 std::shared_ptr共享指针
        • 3.1.1.3 std::weak_ptr弱指针
      • 3.1.2 C++中的引用与指针的区别
      • 3.1.3 解释C++中的虚函数和如何使用它实现多态
      • 3.1.4 解释重载、重写和隐藏在C++中的区别
      • 3.1.5 解释C++中的构造函数和析构函数
    • 3.2 Python
      • 3.2.1 python标准库常见的数据类型
      • 3.2.2 def func(*args, **kwargs):函数中,*args, **kwargs是什么意思?args和kwargs各是什么类型?
      • 3.2.3 从一个字符串str变量中找到含有科学计数法的部分
      • 3.2.4 a,b两个变量在不使用中间变量的情况下如何交换值
      • 3.2.5 简述一下装饰器是什么,并设计一个统计函数运行时间的装饰器
      • 3.2.6
    • 3.3 Cuda
      • 3.3.1 描述GPU的内存层次结构
      • 3.3.2 如何在CUDA中管理内存(分配、释放、数据传输)?
      • 3.3.3 什么是核函数(Kernel)?如何定义和调用?
      • 3.3.4 解释CUDA线程的层次结构
  • 4. 视觉相关问题
    • 4.1 如何计算一组数据的信息熵?
    • 4.2 什么是过拟合和欠拟合?
    • 4.3 什么是模型的偏差和方差?
    • 4.4 准确度(Accuracy)、精确率(Precision)、召回率(Recall) 和 F1值
    • 4.5 计算bbox的iou
    • 4.6 在使用pytorch训练模型时,我只有32G的RAM, 如何训练512GB的数据呢?
    • 4.7 Pytorch和tensorflow计算图区别
  • 5. 模型部署
    • 5.1 使用tensorrt10设计一个tensorrt模型推理的包装类
    • 5.2 设计神经网络
  • 6. AI问题

1. 数据结构

1.1 时间复杂度

以下述代码为例:

int n = 100;
for (int i = 0; i < n; i++)
{cout<<"test01"<<endl;
}

为了方便讨论,这里我们把每一条语句的执行时间都看做是一样的,记为一个时间单元
这里的,红色框皆为运行1次的,蓝色框运行n+1次,橙色框运行n次,总共花费了3n+3个时间单元。可以看出,程序消耗的时间和这里的n呈现出线性关系
在这里插入图片描述
那么,运行时间的函数可以表示为:T(n) = 3n + 3,其中的n被我们称为问题的规模,其实就是你处理问题的大小。
我们通常会对函数进行简化,使其仍然能够表示原有的函数趋势特性。
我们一般只关心随着问题规模n趋于无穷时,函数中对函数结果影响最大的项,也就是最高次项,简化后,T(n) = 3n + 3 ~ f(n) = n
时间复杂度可以表示某个算法的运行时间的趋势,大致地度量算法效率的好坏。
总结:
计算时间复杂度的流程:
1、得出运行时间的函数;
2、对函数进行简化。
ps:(1)用常数1来取代运行时间中所有加法常数;
(2)修改后的函数中,只保留最高阶项;
(3)如果最高阶项存在且不是1,则忽略这个项的系数

技巧:
一般,只要看看最内层的语句执行次数的规律就行了,这个内层打印语句随着问题规模n的增加会呈线性增加,直接就可以判定复杂度为O(n)。

for (int i = 0; i < n; i++)
{for (int j = 0; j < n; j++){cout<<"test01"<<endl;  // 最内层语句}
}

2. 算法问题

2.1 两数之和

// 暴力枚举法
class Solution {
public:vector<int> twoSum(vector<int>& nums, int target) {int n = nums.size();for (int i = 0; i < n; ++i) {for (int j = i + 1; j < n; ++j) {if (nums[i] + nums[j] == target) {return {i, j};}}}return {};}
};

2.2 递归求二叉树的深度

#include <iostream>
using namespace std;// 定义二叉树节点结构体
struct TreeNode {int val;             // 节点值TreeNode *left;      // 左子节点指针TreeNode *right;     // 右子节点指针TreeNode(int x) : val(x), left(NULL), right(NULL) {}  // 构造函数初始化
};// 递归计算二叉树的最大深度
int maxDepth(TreeNode* root) {// 如果节点为空,深度为 0if (root == NULL)return 0;// 递归求左子树和右子树的深度int leftDepth = maxDepth(root->left);int rightDepth = maxDepth(root->right);// 当前节点的深度等于左右子树深度的较大值加 1return max(leftDepth, rightDepth) + 1;
}int main() {// 创建一个简单的二叉树/*1/ \2   3/ \4   5*/TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);// 计算二叉树的最大深度cout << "The maximum depth of the binary tree is: " << maxDepth(root) << endl;return 0;
}

2.3 一个由0和1组成数组中,计算出这里面连续1的最大数

#include <iostream>
#include <vector>
using namespace std;int findMaxConsecutiveOnes(vector<int>& nums) {int maxCount = 0;    // 最大连续1的数量int currentCount = 0;  // 当前连续1的数量for (int i = 0; i < nums.size(); i++) {if (nums[i] == 1) {currentCount++;    // 如果当前数字是1,增加连续1的数量} else {maxCount = max(maxCount, currentCount);  // 遇到0时更新最大连续1的数量currentCount = 0;  // 重置当前连续1的数量}}// 可能数组最后的元素是1,循环结束时没有机会更新最大值maxCount = max(maxCount, currentCount);return maxCount;
}int main() {vector<int> nums = {1, 1, 0, 1, 1, 1};  // 示例数组int result = findMaxConsecutiveOnes(nums);cout << "The maximum number of consecutive 1s is: " << result << endl;return 0;
}

3. C++、Python、Cuda问题

3.1 C++

3.1.1 智能指针

智能指针是 C++ 中用于自动管理动态分配内存的一种对象,主要用于解决传统指针在内存管理方面的不足。它们能够在对象不再需要时自动释放内存,从而减少内存泄漏悬挂指针等问题 。
内存泄漏:
程序在运行时动态分配了内存(通常通过 new 或 malloc),但是没有在使用完毕后释放这部分内存(使用 delete 或 free)。这导致程序占用的内存逐渐增加,最终可能耗尽可用内存,导致性能下降或程序崩溃。
悬挂指针:
一个指针指向了已经被释放或未定义的内存地址。

3.1.1.1 std::unique_ptr独占指针

特性:
1.表示对动态分配对象的唯一所有权
2.不允许复制,但可以转移所有权(使用 std::move)。
3.在 unique_ptr 超出作用域时,自动释放所指向的内存。

#include <iostream>
#include <memory>void example() {std::unique_ptr<int> ptr1(new int(10)); // 动态分配一个整数std::cout << *ptr1 << std::endl; // 输出 10// std::unique_ptr<int> ptr2 = ptr1; // 错误,不能复制std::unique_ptr<int> ptr2 = std::move(ptr1); // 转移所有权std::cout << *ptr2 << std::endl; // 输出 10// ptr1 现在为空
}
3.1.1.2 std::shared_ptr共享指针

特性:
1.表示对动态分配对象的共享所有权
2.允许多个 shared_ptr 指向同一个对象,使用引用计数来管理内存。
3.当最后一个指向该对象的 shared_ptr 被销毁时,内存将被释放

#include <iostream>
#include <memory>void example() {std::shared_ptr<int> ptr1(new int(20)); // 动态分配一个整数std::cout << *ptr1 << std::endl; // 输出 20std::shared_ptr<int> ptr2 = ptr1; // 共享所有权std::cout << *ptr2 << std::endl; // 输出 20std::cout << ptr1.use_count() << std::endl; // 输出 2,表示有两个指针共享同一对象
}
3.1.1.3 std::weak_ptr弱指针

特性:
1.主要用于打破 shared_ptr 的循环引用问题。
2.不控制对象的生命周期,不增加引用计数。
3.可以通过 lock() 方法获得一个 shared_ptr。
作用:用来解决shared_ptr相互引用导致的死锁问题
当两个或多个 std::shared_ptr 互相持有对方的引用时,它们的引用计数不会降到零,导致内存无法被释放,这就是所谓的循环引用或死锁

#include <iostream>
#include <memory>class B; // 前向声明class A {
public:std::shared_ptr<B> b_ptr;~A() { std::cout << "A destroyed\n"; }
};class B {
public:std::shared_ptr<A> a_ptr;~B() { std::cout << "B destroyed\n"; }
};int main() {std::shared_ptr<A> a(new A);std::shared_ptr<B> b(new B);a->b_ptr = b;b->a_ptr = a;// a 和 b 互相引用,导致无法释放return 0;
}

用 std::weak_ptr 解决问题

#include <iostream>
#include <memory>class B; // 前向声明class A {
public:std::shared_ptr<B> b_ptr;~A() { std::cout << "A destroyed\n"; }
};class B {
public:std::weak_ptr<A> a_ptr; // 使用 weak_ptr~B() { std::cout << "B destroyed\n"; }
};int main() {std::shared_ptr<A> a(new A);std::shared_ptr<B> b(new B);a->b_ptr = b;b->a_ptr = a; // 现在使用 weak_ptr// a 和 b 之间的引用关系不会阻止内存的释放return 0;
}

3.1.2 C++中的引用与指针的区别

引用
相当于给变量起“别名”,在c++内部其实是一个“指针常量”,必须初始化,且一旦初始化后,就不能改变。
指针
是一个变量,它存储另一个变量的内存地址。通过指针,可以访问和修改指针所指向的变量。

3.1.3 解释C++中的虚函数和如何使用它实现多态

虚函数是在基类中用virtual声明的函数,它允许在派生类中重写。当使用基类指针引用指向子类时候,程序会根据实际对象的类型(即派生类)来决定调用哪个版本的函数,而不是基类版本。这种行为称为“动态绑定”或“晚绑定”。

3.1.4 解释重载、重写和隐藏在C++中的区别

1、重载
重载是指在同一个作用域中,可以定义多个同名的函数或运算符,它们的参数列表必须不同(参数的数量或类型不同)。C++允许函数重载以提高代码的可读性和灵活性。编译时多态
2、重写
重写是指在派生类中重新定义基类中已经存在的虚函数。重写允许子类提供特定的实现,并且实现与基类的函数具有相同的名称和参数列表。重写用于实现运行时多态性。动态绑定

3、隐藏
隐藏是指在派生类中定义了一个与基类中同名的函数或变量,导致基类中的函数或变量在派生类中不可见。这种情况下,基类的同名成员函数或变量不会被重写,而是被隐藏。

#include <iostream>class Base {
public:void display() {std::cout << "Base class display function." << std::endl;}
};class Derived : public Base {
public:void display(int i) { // 隐藏基类的display函数std::cout << "Derived class display function with int: " << i << std::endl;}
};int main() {Derived d;d.display(10); // 调用派生类的display(int)函数// d.display(); // 错误: 基类的display()不可见d.Base::display(); // 调用基类的display()函数return 0;
}

3.1.5 解释C++中的构造函数和析构函数

构造函数:
是一种特殊的成员函数,在对象创建时被自动调用。它的主要作用是初始化对象的属性或分配资源。构造函数的名称与类名相同,并且没有返回类型(包括void)。
析构函数:
是一种特殊的成员函数,在对象生命周期结束时被自动调用。它的主要作用是释放对象在构造时分配的资源(如内存、文件句柄等)。析构函数的名称与类名相同,但在名称前加上~符号,并且没有参数和返回类型。

3.2 Python

python_310">3.2.1 python标准库常见的数据类型

答:
int、float、str、bool、list、set、tuple、dict

3.2.2 def func(*args, **kwargs):函数中,*args, **kwargs是什么意思?args和kwargs各是什么类型?

答:
非关键字参数和关键字参数;tuplie、dict。

3.2.3 从一个字符串str变量中找到含有科学计数法的部分

正则表达式就是一种匹配字符串模式的“公式”。通过正则表达式,你可以从一段文字中查找、替换或验证符合特定模式的字符串。

string = “xy sfas 1e-6 fs!”

python">import re
string = "xy sfas 1e-6 fs!"# 使用正则表达式匹配科学计数法
pattern = r'[-+]?\d*\.?\d+([eE][-+]?\d+)?'
matches = re.findall(pattern, string)# 打印匹配到的科学计数法部分
print(matches)

string = "xsdaaf2e+9as.

python">import re
string = "xsdaaf2e+9as"# 使用正则表达式匹配科学计数法
pattern = r'[-+]?\d*\.?\d+[eE][-+]?\d+'
matches = re.findall(pattern, string)# 打印匹配到的科学计数法部分
print(matches)

3.2.4 a,b两个变量在不使用中间变量的情况下如何交换值

python">a = 5
b = 10a, b = b, aprint(a)  # 输出: 10
print(b)  # 输出: 5

3.2.5 简述一下装饰器是什么,并设计一个统计函数运行时间的装饰器

3.2.6

(1) 定义一个名为car的类,它有两个属性:“color”和“speed”。然后创建一个实例并返回“speed”。

python">class Car:def __init__(self, color, speed):self.color = color  # 定义颜色属性self._speed = speed  # 使用单下划线标记为“保护”属性def get_speed(self):return self._speed  # 返回 speed# 创建 Car 类的实例
my_car = Car(color="red", speed=120)# 返回 speed
car_speed = my_car.get_speed()
print(f"The speed of the car is: {car_speed} km/h")

(2) 如果我想要访问speed,又想让用户不能修改,怎么实现?(编程形式回答)

python">class Car:def __init__(self, color, speed):self.color = color  # 定义颜色属性self._speed = speed  # 使用单下划线标记为“保护”属性def get_speed(self):return self._speed  # 返回 speed# 创建 Car 类的实例
my_car = Car(color="red", speed=120)# 访问 speed
car_speed = my_car.get_speed()
print(f"The speed of the car is: {car_speed} km/h")# 尝试修改 speed(这将不起作用)
try:my_car._speed = 150  # 尝试直接修改 speed
except AttributeError as e:print(f"Error: {e}")# 查看 speed 仍然是原来的值
print(f"Speed after attempting modification: {my_car.get_speed()} km/h")

3.3 Cuda

3.3.1 描述GPU的内存层次结构

GPU的内存层次结构由几个主要部分组成:
1.全局内存(Global Memory):所有线程都可以访问的大容量存储空间,但访问延迟最高。
2.共享内存(Shared Memory):在同一个线程块(Block)内的线程间共享的低延迟内存。
3.寄存器(Registers):每个线程独有的最快速的存储空间。
4.常量和纹理内存(Constant and Texture Memory):缓存,用于存储频繁访问的数据,可以提高某些类型数据的访问效率。

3.3.2 如何在CUDA中管理内存(分配、释放、数据传输)?

在CUDA中,内存管理涉及在GPU设备的全局内存分配和释放内存,以及在主机(CPU)设备(GPU)之间传输数据
1.分配内存:使用cudaMalloc()函数在GPU上分配内存。
2.释放内存:使用cudaFree()函数释放之前分配的内存。
3.数据传输:使用cudaMemcpy()函数在主机和设备之间复制数据。

3.3.3 什么是核函数(Kernel)?如何定义和调用?

核函数是在CUDA中执行的特殊函数,可以在GPU上并行执行多个线程。核函数通过__global__修饰符定义,并且只能从主机代码调用。

__global__ void kernelName(参数列表) {// 核函数代码
}

调用核函数时,需要指定执行配置,包括线程块的数量和每个线程块中的线程数量:

kernelName<<<numBlocks, threadsPerBlock>>>(参数);

3.3.4 解释CUDA线程的层次结构

CUDA的线程组织为三级层次结构:
1.网格(Grid):整个核函数的线程块集合。
2.线程块(Block):一组可以协作的线程,共享同一块共享内存。
3.线程(Thread):执行核函数的最小单元

4. 视觉相关问题

4.1 如何计算一组数据的信息熵?

在这里插入图片描述

假设你有一个数据集,包含 4 种类别,分别为 A、B、C 和 D,且它们的出现频率如下:
A 出现了 4 次;B 出现了 2 次;C 出现了 1 次;D 出现了 1 次。
P(A)= 4 / 8 = 0.5;P(B)= 2 / 8 = 0.25;P©= 1 / 8 = 0.125;P(D)= 2 / 8 = 0.125;
在这里插入图片描述

4.2 什么是过拟合和欠拟合?

过拟合:是指模型在训练数据上表现非常好,但在测试数据(即未见过的数据)上表现很差的情况。这种现象通常发生在模型过于复杂,能够“记住”训练数据中的噪声或特征,从而对训练数据做出过度拟合。
解决方法:
1、使用更多的训练数据。
2、增加正则化(如L1或L2正则化)以限制模型的复杂度。
3、采用较小的模型,减少参数数量,避免模型过于复杂。
欠拟合:是指模型在训练数据和测试数据上都表现不佳的情况。这意味着模型过于简单,无法有效学习训练数据中的规律,甚至训练数据上的误差也很大。
解决方法:
1、使用更复杂的模型(增加参数或使用更复杂的算法)。
2、增加特征维度或进行更好的特征提取。
3、增加训练时间,让模型有更多机会学习数据中的规律。

4.3 什么是模型的偏差和方差?

偏差:
衡量的是模型预测值与真实值之间的差距,是一种系统性的误差,通常与模型的假设有关。偏差表示模型的拟合能力,如果偏差过高,说明模型假设过于简单,无法正确地表达数据的内在模式,导致欠拟合
方差:
方差:衡量的是模型对训练数据的敏感性,即当使用不同的训练数据集时,模型预测结果的波动程度。
高方差:模型过于依赖训练数据,训练时能够很好地拟合训练数据中的细节(甚至是噪声),但当应用于新的数据时,表现可能会显著下降。这样的模型通常存在过拟合问题。

4.4 准确度(Accuracy)、精确率(Precision)、召回率(Recall) 和 F1值

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.5 计算bbox的iou

python">def calculate_iou(bbox1, bbox2):x1_min, y1_min, x1_max, y1_max = bbox1x2_min, y2_min, x2_max, y2_max = bbox2# 计算交集x_inter_min = max(x1_min, x2_min)y_inter_min = max(y1_min, y2_min)x_inter_max = min(x1_max, x2_max)y_inter_max = min(y1_max, y2_max)# 交集的面积inter_area = max(0, x_inter_max - x_inter_min) * max(0, y_inter_max - y_inter_min)# 各自的面积area1 = (x1_max - x1_min) * (y1_max - y1_min)area2 = (x2_max - x2_min) * (y2_max - y2_min)# 并集的面积union_area = area1 + area2 - inter_area# IoUiou = inter_area / union_area if union_area > 0 else 0return iou# 示例
bbox1 = [0, 0, 2, 2]
bbox2 = [1, 1, 3, 3]
iou = calculate_iou(bbox1, bbox2)
print("IoU:", iou)

4.6 在使用pytorch训练模型时,我只有32G的RAM, 如何训练512GB的数据呢?

将数据分为多个小批次(mini-batches),每次只加载一个批次的数据到内存中进行训练。PyTorch 的 DataLoader 可以轻松实现这一点。

python">from torch.utils.data import DataLoader, Datasetclass MyDataset(Dataset):def __init__(self, data_file):# 读取数据文件(例如,使用 h5py, pandas 等)self.data = ...  # 数据读取逻辑def __len__(self):return len(self.data)def __getitem__(self, idx):# 返回单个数据样本return self.data[idx]# 创建数据集和数据加载器
dataset = MyDataset("path/to/your/data")
data_loader = DataLoader(dataset, batch_size=32, shuffle=True)for batch in data_loader:# 进行模型训练pass

4.7 Pytorch和tensorflow计算图区别

Pytorch是动态计算图,tensorflow是静态计算图。

5. 模型部署

5.1 使用tensorrt10设计一个tensorrt模型推理的包装类

使用tensorrt10设计一个tensorrt模型推理的包装类,包含构造函数和forward函数。要求构造函数输入序列化模型路径,初始化完毕后,推理时模拟pytorch的forward函数效果,输入数据,输出最终结果。

5.2 设计神经网络

如何用pytorch设计一个简单的神经网络(三层卷积,两层全连接,激活函数Relu,池化,正则化层), 并生成随机数输入给网络,得出结果。

python">import torch
import torch.nn as nn
import torch.nn.functional as F
class SimpleCNN(nn.Module):def __init__(self):super(SimpleCNN, self).__init__()# 第一层卷积self.conv1 = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3, stride=1, padding=1)  # 输入通道1,输出通道16self.bn1 = nn.BatchNorm2d(16)  # Batch Normalizationself.pool = nn.MaxPool2d(kernel_size=2, stride=2)  # 最大池化# 第二层卷积self.conv2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, stride=1, padding=1)self.bn2 = nn.BatchNorm2d(32)# 第三层卷积self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1)self.bn3 = nn.BatchNorm2d(64)# 全连接层self.fc1 = nn.Linear(64 * 7 * 7, 128)  # 假设输入图像为28x28,经过池化后为7x7self.fc2 = nn.Linear(128, 10)  # 输出10个类别def forward(self, x):# 第一层x = self.conv1(x)x = self.bn1(x)x = F.relu(x)x = self.pool(x)# 第二层x = self.conv2(x)x = self.bn2(x)x = F.relu(x)x = self.pool(x)# 第三层x = self.conv3(x)x = self.bn3(x)x = F.relu(x)x = self.pool(x)# 展平x = x.view(-1, 64 * 7 * 7)# 全连接层x = self.fc1(x)x = F.relu(x)x = self.fc2(x)return x

6. AI问题

1、是否独立部署GPT?


http://www.ppmy.cn/news/1561923.html

相关文章

内蒙古水系详细很全shp格式arcgis软件无偏移坐标下载后内容测评

标题中的“内蒙古水系详细很全shp格式arcgis软件无偏移坐标”指的是一个地理信息系统&#xff08;GIS&#xff09;数据集&#xff0c;该数据集详细记录了内蒙古地区的水系信息&#xff0c;并以ESRI公司的标准矢量数据格式——Shapefile&#xff08;.shp&#xff09;进行存储。S…

C++虚函数(八股总结)

什么是虚函数 虚函数是在父类中定义的一种特殊类型的函数&#xff0c;允许子类重写该函数以适应其自身需求。虚函数的调用取决于对象的实际类型&#xff0c;而不是指针或引用类型。通过将函数声明为虚函数&#xff0c;可以使继承层次结构中的每个子类都能够使用其自己的实现&a…

第14章 MySQL事务日志

第14章 MySQL事务日志 事务有4种特性&#xff1a;原子性、一致性、隔离性和持久性。那么事务的四种特性到底是基于什么机制实现呢&#xff1f; 事务的隔离性由锁机制实现。而事务的原子性、一致性和持久性由事务的 redo 日志和undo 日志来保证。 REDO LOG 称为重做日志&#…

ElasticSearch | Elasticsearch与Kibana页面查询语句实践

关注&#xff1a;CodingTechWork 引言 在当今大数据应用中&#xff0c;Elasticsearch&#xff08;简称 ES&#xff09;以其高效的全文检索、分布式处理能力和灵活的查询语法&#xff0c;广泛应用于各类日志分析、用户行为分析以及实时数据查询等场景。通过 ES&#xff0c;用户…

C# 对象和类型(结构)

❝ 类和结构的区别 字段、属性和方法 按值和引用传送参数 方法重载 构造函数和静态构造函数 只读字段 Object类&#xff0c;其他类型都从该类派生而来 结构 如何将类保持在堆中&#xff0c;通过这种方式可以在数据的生存期上获得很大的灵活性&#xff0c;但性能会有一定的损失。…

maven的中国镜像有哪些

根据您的请求&#xff0c;以下是一些可用的 Maven 中国镜像&#xff1a; 阿里云 官网&#xff1a;阿里云 Maven 镜像配置&#xff1a;<mirror><id>aliyunmaven</id><mirrorOf>*</mirrorOf><name>阿里云公共仓库</name><url>…

大麦抢票科技狠活

仅供学习参考&#xff0c;切勿再令您所爱的人耗费高昂的价格去购置黄牛票 ⚠️核心内容参考: 据悉&#xff0c;于购票环节&#xff0c;大麦凭借恶意流量清洗技术&#xff0c;于网络层实时甄别并阻拦凭借自动化手段发起下单请求的流量&#xff0c;强化对刷票脚本、刷票软件以及…

NRF24L01模块STM32通信-通信初始化

目录 前言 一、IO口初始化 二、模拟SPI的基础代码 1.一些代码的宏定义 2.起始信号 3.CS,SCK,MOSI操作 4.MISO,IRQ操作 三.中间层代码 1.字节的输入和读取 2.写操作 3.读操作 四.应用层代码 1.24L01的检测 2.在main函数进行简单验证 3.24L01宏定义的代码 总结 前…