当前位置: 首页 > news >正文

JavaScript性能优化实战(5):数据结构与算法性能优化

JavaScript中常用数据结构性能对比

数据结构的选择对JavaScript应用的性能有着决定性的影响。不同的数据结构在不同操作上各有优劣,选择合适的数据结构能显著提升应用性能。本节将对JavaScript中常用的数据结构进行全面的性能对比分析。

基本数据结构时间复杂度概览

首先,让我们回顾JavaScript中常用数据结构的时间复杂度:

数据结构访问搜索插入删除遍历
数组(Array)O(1)O(n)O(n)*O(n)*O(n)
对象(Object)O(1)O(n)O(1)O(1)O(n)
MapO(1)O(1)O(1)O(1)O(n)
SetN/AO(1)O(1)O(1)O(n)
WeakMap/WeakSetO(1)O(1)O(1)O(1)N/A

*注:数组在末尾插入/删除是O(1),在中间或开头操作则为O(n)

数组(Array)性能特点

数组是JavaScript中最基础的集合类型,具有以下性能特点:

优势
  1. 随机访问效率高: 通过索引访问数组元素的时间复杂度为O(1)
  2. 尾部操作高效: push()pop()操作的时间复杂度为O(1)
  3. 内置优化: JavaScript引擎对数组迭代有特殊优化,for循环和数组方法如mapfilter等性能通常很好
劣势
  1. 头部插入删除慢: unshift()shift()操作的时间复杂度为O(n),因为需要移动所有元素
  2. 查找慢: 在未排序数组中查找元素需要O(n)时间复杂度
  3. 稀疏数组效率低: 含有大量空位的稀疏数组会浪费内存
// 数组性能测试示例
function arrayPerformanceTest() {console.time('Array操作性能测试');const arr = [];const iterations = 100000;// 测试尾部插入 (高效 O(1))console.time('Array尾部插入');for (let i = 0; i < iterations; i++) {arr.push(i);}console.timeEnd('Array尾部插入');// 测试头部插入 (低效 O(n))const smallArr = [];console.time('Array头部插入');for (let i = 0; i < 1000; i++) { // 使用较小的数量,因为这个操作很慢smallArr.unshift(i);}console.timeEnd('Array头部插入');// 测试随机访问 (高效 O(1))console.time('Array随机访问');let sum = 0;for (let i = 0; i < iterations; i++) {sum += arr[Math.floor(Math.random() * arr.length)];}console.timeEnd('Array随机访问');// 测试查找元素 (低效 O(n))console.time('Array查找元素');for (let i = 0; i < 1000; i++) {arr.indexOf(Math.floor(Math.random() * iterations));}console.timeEnd('Array查找元素');console.timeEnd('Array操作性能测试');
}

对象(Object)性能特点

JavaScript对象是基于哈希表实现的键值对集合,具有以下性能特点:

优势
  1. 键值访问高效: 通过键访问值的时间复杂度为O(1)
  2. 属性增删高效: 添加和删除属性的时间复杂度为O(1)
  3. 内存占用小: 相比Map,普通对象的内存占用更小
劣势
  1. 键类型限制: 只能使用字符串或Symbol作为键
  2. 无序性: 属性的迭代顺序不可靠(ES2015后有一定的顺序保证,但不完全可靠)
  3. 原型链查找: 当属性不存在时,会沿原型链查找,可能影响性能
// 对象性能测试示例
function objectPerformanceTest() {console.time('Object操作性能测试');const obj = {};const iterations = 100000;// 测试属性设置 (高效 O(1))console.time('Object属性设置');for (let i = 0; i < iterations; i++) {obj[`key${i}`] = i;}console.timeEnd('Object属性设置');// 测试属性访问 (高效 O(1))console.time('Object属性访问');let sum = 0;for (let i = 0; i < iterations; i++) {const key = `key${Math.floor(Math.random() * iterations)}`;sum += obj[key] || 0;}console.timeEnd('Object属性访问');// 测试属性检查 (高效 O(1))console.time('Object属性检查');for (let i = 0; i < 1000; i++) {const key = `key${Math.floor(Math.random() * iterations * 2)}`; // 包含一些不存在的键key in obj;}console.timeEnd('Object属性检查');// 测试对象遍历 (O(n))console.time('Object遍历');sum = 0;for (const key in obj) {if (Object.prototype.hasOwnProperty.call(obj, key)) {sum += obj[key];}}console.timeEnd('Object遍历');console.timeEnd('Object操作性能测试');
}

Set集合性能特点

Set是ES6引入的集合类型,用于存储唯一值,具有以下性能特点:

优势
  1. 值唯一性: 自动去重,适合需要唯一性的场景
  2. 高效成员检查: has()方法的时间复杂度为O(1)
  3. 迭代顺序稳定: 迭代顺序与插入顺序一致
劣势
  1. 内存占用大: 相比数组可能消耗更多内存
  2. 无索引访问: 不能像数组一样通过索引直接访问元素
  3. 不支持搜索: 无法直接根据值部分特征查找元素
// Set性能测试示例
function setPerformanceTest() {console.time('Set操作性能测试');const set = new Set();const iterations = 100000;// 测试添加元素 (高效 O(1))console.time('Set添加元素');for (let i = 0; i < iterations; i++) {set.add(i);}console.timeEnd('Set添加元素');// 测试成员检查 (高效 O(1))console.time('Set成员检查');for (let i = 0; i < iterations; i++) {set.has(Math.floor(Math.random() * iterations * 2)); // 包含一些不存在的值}console.timeEnd('Set成员检查');// 测试删除元素 (高效 O(1))console.time('Set删除元素');for (let i = 0; i < 1000; i++) {set.delete(Math.floor(Math.random() * iterations));}console.timeEnd('Set删除元素');// 测试遍历 (O(n))console.time('Set遍历');let sum = 0;for (const value of set) {sum += value;}console.timeEnd('Set遍历');console.timeEnd('Set操作性能测试');
}

Map映射性能特点

Map是ES6引入的键值对集合,比普通对象更强大灵活,具有以下性能特点:

优势
  1. 键类型灵活: 可以使用任何类型的值作为键,包括对象和函数
  2. 迭代顺序稳定: 迭代顺序与插入顺序一致
  3. 专用方法: 提供了size属性和clear()等专用方法
劣势
  1. 内存占用大: 相比普通对象消耗更多内存
  2. 序列化不便: 不能直接JSON序列化
  3. 旧浏览器支持差: 在较旧的浏览器中可能需要polyfill
// Map性能测试示例
function mapPerformanceTest() {console.time('Map操作性能测试');const map = new Map();const iterations = 100000;// 测试设置键值 (高效 O(1))console.time('Map设置键值');for (let i = 0; i < iterations; i++) {map.set(`key${i}`, i);}console.timeEnd('Map设置键值');// 测试获取值 (高效 O(1))console.time('Map获取值');let sum = 0;for (let i = 0; i < iterations; i++) {const key = `key${Math.floor(Math.random() * iterations)}`;const value = map.get(key);if (value !== undefined) {sum += value;}}console.timeEnd('Map获取值');// 测试键存在检查 (高效 O(1))console.time('Map键存在检查');for (let i = 0; i < iterations; i++) {map.has(`key${Math.floor(Math.random() * iterations * 2)}`); // 包含一些不存在的键}console.timeEnd('Map键存在检查');// 测试遍历 (O(n))console.time('Map遍历');sum = 0;for (const [key, value] of map) {sum += value;}console.timeEnd('Map遍历');console.timeEnd('Map操作性能测试');
}

综合性能对比

以下是在V8引擎上进行的常见操作性能对比(值越小越好,单位:毫秒):

操作ArrayObjectSetMap
添加100万项1,2507801,8002,100
查找操作(100万次)12,800130120150
删除操作(1万次)11,500*250270280
遍历(100万项)28570105130

*注:数组删除采用splice方法,若使用过滤创建新数组则更快

数据结构选择的实用建议

基于上述性能特点,以下是选择适当数据结构的建议:

  1. 选择数组的场景:

    • 需要保持元素顺序
    • 主要操作是遍历和尾部添加/删除
    • 需要通过数字索引直接访问元素
  2. 选择对象的场景:

    • 需要简单的字符串键到值的映射
    • 关注内存占用和JSON序列化
    • 不需要特殊的集合操作和保证迭代顺序
  3. 选择Set的场景:

    • 需要存储唯一值集合
    • 频繁检查值是否存在
    • 需要保持插入顺序
  4. 选择Map的场景:

    • 需要使用非字符串键
    • 需要键值对的顺序与添加顺序一致
    • 需要频繁添加和删除键值对
// 数据结构选择示例
function chooseRightDataStructure() {// 场景1: 需要快速查找操作// 错误选择: 数组const userIds = [1001, 1002, 1003, /* ... 更多ID */];const isUserAuthorized = (id) => userIds.includes(id); // O(n)时间复杂度// 正确选择: Setconst userIdSet = new Set([1001, 1002, 1003, /* ... 更多ID */]);const isUserAuthorizedOptimized = (id) => userIdSet.has(id); // O(1)时间复杂度// 场景2: 需要根据ID快速查找对象// 错误选择: 数组const users = [{ id: 1001, name: 'Alice' },{ id: 1002, name: 'Bob' },// ... 更多用户];const findUser = (id) => users.find(user => user.id === id); // O(n)时间复杂度// 正确选择: Map或Objectconst userMap = new Map(users.map(user => [user.id, user]));const findUserOptimized = (id) => userMap.get(id); // O(1)时间复杂度// 或者使用对象const userObject = {};users.forEach(user => {userObject[user.id] = user;});const findUserWithObject = (id) => userObject[id]; // O(1)时间复杂度
}

真实场景性能优化案例

案例1: 大量数据的唯一性检查
// 电商网站商品去重
function deduplicateProducts(products) {// 方法1: 使用Array.filter (低效)console.time('Array方法');const uniqueProducts1 = products.filter((product, index, self) =>index === self.findIndex(p => p.id === product.id));console.timeEnd('Array方法');// 方法2: 使用Set和Map (高效)console.time('Set+Map方法');const seen = new Set();const uniqueProducts2 = products.filter(product => {if (seen.has(product.id)) {return false;}seen.add(product.id);return true;});console.timeEnd('Set+Map方法');return uniqueProducts2;
}// 测试
const sampleProducts = Array.from({ length: 10000 }, (_, i) => ({id: Math.floor(i / 3), // 制造重复数据name: `Product ${i}`,price: Math.random() * 1000
}));deduplicateProducts(sampleProducts);
// 输出示例:
// Array方法: 850.123ms
// Set+Map方法: 5.678ms
案例2: 频繁的查找和更新操作
// 购物车商品管理
class ShoppingCart {constructor() {// 低效实现: 使用数组存储this.itemsArray = [];// 高效实现: 使用Map存储this.itemsMap = new Map();}// 添加商品addItemArray(id, name, price, quantity) {const existingItem = this.itemsArray.find(item => item.id === id);if (existingItem) {existingItem.quantity += quantity;} else {this.itemsArray.push({ id, name, price, quantity });}}addItemMap(id, name, price, quantity) {if (this.itemsMap.has(id)) {const item = this.itemsMap.get(id);item.quantity += quantity;} else {this.itemsMap.set(id, { id, name, price, quantity });}}// 移除商品removeItemArray(id) {const index = this.itemsArray.findIndex(item => item.id === id);if (index !== -1) {this.itemsArray.splice(index, 1);}}removeItemMap(id) {this.itemsMap.delete(id);}// 获取商品详情getItemArray(id) {return this.itemsArray.find(item => item.id === id);}getItemMap(id) {return this.itemsMap.get(id);}// 更新商品数量updateQuantityArray(id, quantity) {const item = this.getItemArray(id);if (item) {item.quantity = quantity;}}updateQuantityMap(id, quantity) {const item = this.getItemMap(id);if (item) {item.quantity = quantity;}}
}// 测试性能
function testShoppingCartPerformance() {const cart = new ShoppingCart();const iterations = 10000;// 填充数据for (let i = 0; i < 100; i++) {cart.addItemArray(i, `Product ${i}`, Math.random() * 100, 1);cart.addItemMap(i, `Product ${i}`, Math.random() * 100, 1);}// 测试查找性能console.time('Array查找');for (let i = 0; i < iterations; i++) {cart.getItemArray(Math.floor(Math.random() * 100));}console.timeEnd('Array查找');console.time('Map查找');for (let i = 0; i < iterations; i++) {cart.getItemMap(Math.floor(Math.random() * 100));}console.timeEnd('Map查找');// 测试更新性能console.time('Array更新');for (let i = 0; i < iterations; i++) {cart.updateQuantityArray(Math.floor(Math.random() * 100),Math.floor(Math.random() * 5) + 1);}console.timeEnd('Array更新');console.time('Map更新');for (let i = 0; i < iterations; i++) {cart.updateQuantityMap(Math.floor(Math.random() * 100),Math.floor(Math.random() * 5) + 1);}console.timeEnd('Map更新');
}// 运行测试
testShoppingCartPerformance();
// 输出示例:
// Array查找: 420.567ms
// Map查找: 12.345ms
// Array更新: 430.123ms
// Map更新: 15.678ms

结论

在选择数据结构时,需要考虑以下因素:

  1. 访问模式: 考虑数据将如何被访问、修改和遍历
  2. 数据大小: 对于小数据集(100项以下),不同数据结构的性能差异通常不明显
  3. 操作频率: 识别最频繁的操作,并为其优化
  4. 内存限制: 在内存受限环境(如移动设备)中,考虑数据结构的内存占用
  5. 可读性与维护性: 有时稍微牺牲一点性能换取代码可读性是值得的

最后,数据结构选择不是一成不变的,应随着应用需求的变化而调整。在性能关键路径上,适当的数据结构选择可以带来数量级的性能提升。

Map/Set vs Object/Array:选择与性能测试

在前一节中,我们概述了JavaScript中主要数据结构的性能特点。现在,让我们更深入地比较ES6引入的Map/Set与传统的Object/Array,并通过实际测试来验证它们的性能差异。

Map vs Object:关键区别

Map和Object都用于存储键值对,但有几个关键区别:

  1. 键的类型:

    • Object: 键必须是字符串或Symbol
    • Map: 键可以是任何类型,包括对象、函数、原始值
  2. 顺序保证:

    • Object: ES2015后有顺序保证,但有特殊规则(先数字键升序,再字符串键按插入顺序)
    • Map: 保持插入顺序
  3. 内置方法:

    • Object: 需要使用Object.keys()Object.values()等辅助方法遍历
    • Map: 内置forEach方法和迭代器
  4. 大小获取:

    • Object: 需要Object.keys(obj).length获取大小
    • Map: 直接使用map.size属性

Set vs Array:关键区别

Set和Array都用于存储值集合,但同样有显著区别:

  1. 值唯一性:

    • Array: 可以包含重复值
    • Set: 自动去重,只存储唯一值
  2. 查找效率:

    • Array: 使用indexOfincludes需要O(n)时间
    • Set: 使用has方法需要O(1)时间
  3. 元素删除:

    • Array: 需要知道索引,且删除会改变其他元素的索引
    • Set: 直接通过值删除,不影响其他元素
  4. 内置方法:

    • Array: 有丰富的数组方法如mapfilterreduce
    • Set: 方法较少,主要用于添加、删除和检查成员

性能基准测试

让我们通过一系列基准测试来比较Map/Set与Object/Array在不同操作上的性能。

Map vs Object性能测试
// 创建测试数据
function generateTestData(size) {const keys = Array.from({ length: size }, (_, i) => `key${i}`);const values = Array.from({ length: size }, (_, i) => i);return { keys, values };
}// Map vs Object性能测试
function mapVsObjectTest(size = 1000000) {const { keys, values } = generateTestData(size);// 测试创建时间console.time('Object创建');const obj = {};for (let i = 0; i < size; i++) {obj[keys[i]] = values[i];}console.timeEnd('Object创建');console.time('Map创建');const map = new Map();for (let i = 0; i < size; i++) {map.set(keys[i], values[i]);}console.timeEnd('Map创建');// 测试属性访问时间console.time('Object属性访问');let objSum = 0;for (let i = 0; i < size; i++) {objSum += obj[keys[i % size]];}console.timeEnd('Object属性访问');console.time('Map属性访问');let mapSum = 0;for (let i = 0; i < size; i++) {mapSum += map.get(keys[i % size]);}console.timeEnd('Map属性访问');// 测试属性检查console.time('Object属性检查');for (let i = 0; i < size; i++) {const key = `key${i % (size * 2)}`; // 一半存在,一半不存在key in obj;}console.timeEnd('Object属性检查');console.time('Map属性检查');for (let i = 0; i < size; i++) {const key = `key${i % (size * 2)}`; // 一半存在,一半不存在map.has(key);}console.timeEnd('Map属性检查');// 测试键值对遍历console.time('Object遍历');objSum = 0;for (const key in obj) {if (Object.prototype.hasOwnProperty.call(obj, key)) {objSum += obj[key];}}console.timeEnd('Object遍历');console.time('Map遍历');mapSum = 0;for (const [key, value] of map) {mapSum += value;}console.timeEnd('Map遍历');// 测试删除操作const deleteCount = 1000;const deleteKeys = keys.slice(0, deleteCount);console.time('Object删除');for (const key of deleteKeys) {delete obj[key];}console.timeEnd('Object删除');console.time('Map删除');for (const key of deleteKeys) {map.delete(key);}console.timeEnd('Map删除');return {objSize: Object.keys(obj).length,mapSize: map.size};
}// 运行测试
const testResult = mapVsObjectTest();
console.log('测试完成:', testResult);

典型输出结果:

Object创建: 125.634ms
Map创建: 465.789ms
Object属性访问: 110.321ms
Map属性访问: 235.678ms
Object属性检查: 230.456ms
Map属性检查: 180.123ms
Object遍历: 298.765ms
Map遍历: 130.234ms
Object删除: 2.345ms
Map删除: 1.234ms
测试完成: { objSize: 999000, mapSize: 999000 }
Set vs Array性能测试
// Set vs Array性能测试
function setVsArrayTest(size = 1000000) {// 生成测试数据const values = Array.from({ length: size }, (_, i) => i);// 测试创建时间console.time('Array创建');const arr = [];for (let i = 0; i < size; i++) {arr.push(values[i]);}console.timeEnd('Array创建');console.time('Set创建');const set = new Set();for (let i = 0; i < size; i++) {set.add(values[i]);}console.timeEnd('Set创建');// 测试元素查找console.time('Array元素查找');for (let i = 0; i < 10000; i++) {const value = Math.floor(Math.random() * size * 2); // 一半存在,一半不存在arr.includes(value);}console.timeEnd('Array元素查找');console.time('Set元素查找');for (let i = 0; i < 10000; i++) {const value = Math.floor(Math.random() * size * 2); // 一半存在,一半不存在set.has(value);}console.timeEnd('Set元素查找');// 测试遍历性能console.time('Array遍历');let arrSum = 0;for (let i = 0; i < arr.length; i++) {arrSum += arr[i];}console.timeEnd('Array遍历');console.time('Set遍历');let setSum = 0;for (const value of set) {setSum += value;}console.timeEnd('Set遍历');// 测试添加元素(每次都不同的值)console.time('Array添加元素');for (let i = 0; i < 1000; i++) {arr.push(size + i);}console.timeEnd('Array添加元素');console.time('Set添加元素');for (let i = 0; i < 1000; i++) {set.add(size + i);}console.timeEnd('Set添加元素');// 测试删除元素const deleteCount = 1000;const deleteValues = values.slice(0, deleteCount);console.time('Array删除元素');for (const value of deleteValues) {const index = arr.indexOf(value);if (index !== -1) {arr.splice(index, 1);}}console.timeEnd('Array删除元素');console.time('Set删除元素');for (const value of deleteValues) {set.delete(value);}console.timeEnd('Set删除元素');return {arrSize: arr.length,setSize: set.size};
}// 运行测试
const setArrayResult = setVsArrayTest();
console.log('测试完成:', setArrayResult);

典型输出结果:

Array创建: 88.765ms
Set创建: 312.345ms
Array元素查找: 680.123ms
Set元素查找: 

相关文章:

JavaScript性能优化实战(5):数据结构与算法性能优化

JavaScript中常用数据结构性能对比 数据结构的选择对JavaScript应用的性能有着决定性的影响。不同的数据结构在不同操作上各有优劣,选择合适的数据结构能显著提升应用性能。本节将对JavaScript中常用的数据结构进行全面的性能对比分析。 基本数据结构时间复杂度概览 首先,…...

uniapp小程序开发入门01-快速搭建一个空白的项目并预览它

uniapp小程序开发入门01-快速搭建一个空白的项目并预览它&#xff01;由于近期有市场需求和计划&#xff0c;构建一套自己的小程序&#xff0c;所以再次带领大家系统的过一遍&#xff0c;如何使用uniapp程序快速构建一套完整的项目。今天是第一小节&#xff0c;带领大家快速构建…...

UR5 UR5e机器人URDF文件

URDF全称为Unified Robot Description Format,中文可以翻译为“统一机器人描述格式”。与计算机文件中的.txt文本格式、.jpg图像格式等类似,URDF是一种基于XML规范、用于描述机器人结构的格式。根据该格式的设计者所言,设计这一格式的目的在于提供一种尽可能通用(as genera…...

ubuntu20.04安装x11vnc远程桌面

x11vnc是一个VNC服务器, 安装后我们可以不依赖外部的显示设备, 通过网络远程登录ubuntu桌面。 安装x11vnc sudo apt-get install x11vnc 设置VNC登录密码 sudo x11vnc -storepasswd /etc/x11vnc.pwd 设置x11vnc在开机时自动启动 新建如下文件: sudo vi /lib/systemd/sys…...

AKM旭化成微电子全新推出能量收集IC“AP4413系列”

旭化成微电子开始批量生产用于环保发电的电荷控制集成电路&#xff01;优化充电电池的充放电&#xff0c;广泛应用于智能遥控器和蓝牙TMTag等设备。 01 概述 旭化成微电子株式会社&#xff08;AKM&#xff09;开发出面向小型二次电池&#xff08;充电电池&#xff09;的环境…...

机器人行业研究系列报告

新质生产力系列报告&#xff1a;2024年人形机器人核心场景发展洞察研究报告 具身机器人行业现状及未来趋势分析 2025 2025年人形机器人投资策略&#xff0c;量产元年&#xff0c;全球共振&#xff0c;百家争鸣 人形机器人行业深度报告&#xff08;一&#xff09;&#xff1a…...

利用JMeter代理服务器方式实现高效压测

前言 在当今快节奏的互联网时代&#xff0c;确保Web应用和服务能够在高负载下稳定运行变得至关重要。无论是电子商务平台、社交媒体网络还是在线教育服务&#xff0c;用户对网站响应速度和稳定性的期望从未如此之高。因此&#xff0c;性能测试不再是一个可选项&#xff0c;而是…...

NLP高频面试题(五十五)——DeepSeek系列概览与发展背景

大型模型浪潮背景 近年来,大型语言模型(Large Language Model, LLM)领域发展迅猛,从GPT-3等超大规模模型的崛起到ChatGPT的横空出世,再到GPT-4的问世,模型参数规模和训练数据量呈指数级增长。以GPT-3为例,参数高达1750亿,在570GB文本数据上训练,显示出模型规模、数据…...

2015-2023 各省 GDP 数据,用QuickBI 进行数据可视化——堆叠图!

嘿&#xff0c;数据爱好者们&#xff01;今天咱要来一场刺激的数据冒险&#xff0c;深入剖析全国各省的 GDP 数据&#xff0c;而且会借助强大的 QuickBI 工具&#xff0c;用超酷炫的堆叠图让这些数据 “活” 起来&#xff0c;带你一眼看清经济格局&#xff01; 地址&#xff1…...

MySQL优化(持续更新)笔记

一、insert优化 &#xff1a; 之前&#xff1a;项目通常是一条insert一条的执行&#xff0c;每一次都需要与MySQL进行建立连接进行网络传输&#xff0c;效率很低 现在&#xff1a; 1.- 批量插入&#xff08;一条sql就行&#xff0c;一次500-1000&#xff09; 可以与MyBatis…...

MySQL表的操作 -- 表的增删改查

目录 1. 表的创建2. 表的查看3. 表的修改4. 表的删除5. 总结 1. 表的创建 1.查看字符集及效验规则 2. 表的创建 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎;创建用户表1 创建用…...

Java 数组:深度解析

前言 数组作为Java中最基础也是最强大的数据结构之一,其高效性和灵活性在性能关键型应用中无可替代。本文将从进阶使用开始,逐步深入探索Java数组的高级特性和大师级技巧,帮助开发者全面掌握数组技术的精髓。 一、数组基础回顾与性能特性 1.1 数组基本特性对比 特性Java数…...

【基于Qt的QQMusic项目演示第一章】从界面交互到核心功能实现

&#x1f339; 作者: 云小逸 &#x1f91f; 个人主页: 云小逸的主页 &#x1f91f; motto: 要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前&#xff0c;其次就是现在&…...

[Mybatis-plus]

简介 MyBatis-Plus &#xff08;简称 MP&#xff09;是一个 MyBatis的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变。Mybatis-plus官网地址 注意&#xff0c;在引入了mybatis-plus之后&#xff0c;不要再额外引入mybatis和mybatis-spring&#xff0c;避免因为版本…...

【EDA】EDA中聚类(Clustering)和划分(Partitioning)的应用场景

在VLSI物理设计自动化中&#xff0c;聚类&#xff08;Clustering&#xff09;和划分&#xff08;Partitioning&#xff09;是两个互补但目标和应用场景截然不同的关键步骤&#xff0c;其核心区别如下&#xff1a; 一、应用阶段与核心目标 1. 聚类&#xff08;Clustering&…...

PySide与PyQt对比:为何PySide是更优选择

PySide与PyQt对比&#xff1a;为何PySide是更优选择 引言 在Python桌面应用开发领域&#xff0c;Qt框架的绑定库一直是首选方案。两大主要选择—PySide和PyQt&#xff0c;虽然功能相似&#xff0c;但在许可证、性能和支持方面存在显著差异。本文将深入探讨为何PySide通常是更…...

LVGL移植高通矢量字库GT5SLAD3BFA

字库芯片: GT5SLAD3BFA MCU: STM32F429 LVGL版本&#xff1a;V8.4 一&#xff0c;实现gt_read_data() gt_read_data()函数的作用&#xff1a;与字库flash进行通信&#xff0c;函数的定义里调用spi发送数据和接收数据的接口。用户只需要实现该函数&#xff0c;就可以…...

7.0 sharpScada的sql数据的安装

本文介绍开源库SharpScada的配置过程。 1&#xff0c;还原数据库 2.打开SQL server2014配置启动器&#xff0c;并启用Named Pipes,以及TCP/IP 3.启动SQL Server服务中的SQL Server Browser 4.允许远程连接...

杂项知识点

杂项 1 激活函数1.1 sigmoid1.2 tanh1.3 Relu1.4 leakRelu 1 激活函数 常用的激活函数包括sigmoid tanh Relu leakRelu 1.1 sigmoid import torch import numpy as np import matplotlib.pyplot as plt # sigmoid tanh Relu leakRelu ## 1 sigmoid ### 1.1 代码复现sig…...

Android项目升级插件到kotlin 2.1.0后混淆网络请求异常

背景 项目kt插件1.9.24升级到2.1.0后打包编译release网络请求失败了。 retrofit版本2.9.0 错误详情 java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedTypeat retrofit2.m.a(Unknown Source:2477)at retrofit2.K.invoke(U…...

uniapp 仿企微左边公司切换页

示例代码&#xff1a; <template><view class"container"><!-- 遮罩层 --><view class"mask" v-if"showSidebar" click"closeSidebar"></view><!-- 侧边栏 --><view class"sidebar"…...

Milvus(7):Schema、主字段和自动识别

1 Schema Schema 定义了 Collections 的数据结构。在创建一个 Collection 之前&#xff0c;你需要设计出它的 Schema。本页将帮助你理解 Collections 模式&#xff0c;并自行设计一个示例模式。 在 Zilliz Cloud 上&#xff0c;Collection Schema 是关系数据库中一个表的组合&a…...

Liunx服务上MySQL服务导致CPU炸了,使用kill -9 mysqld进程id后,无法启动MySQL

1.top命令后&#xff0c;可以看到mysqld沾满了cpu 2.然后我使用了kill -9 16594&#xff0c;杀死了mysqld进程 3.之后&#xff0c;查看mysql服务状态&#xff0c;发现对应的 www/serve/mysqld 目录不存在 sudo systemctl status mysqld4.使用命令查看操作 www/serve 目录的历…...

Java使用IText7动态生成带审批文本框的PDF文档

Java使用IText7动态生成带审批文本框的PDF文档 文章目录 Java使用IText7动态生成带审批文本框的PDF文档1.构建第一个框的起始坐标2.渲染第一个框3.渲染其他的审批框 测试结果示例 实现思路 使用Canvas进行相对定位和绝对定位来确定文本框内文字位置&#xff0c;用Rectangle通…...

【音视频】AVIO输入模式

内存IO模式 AVIOContext *avio_alloc_context( unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t (*seek)(…...

Android中的多线程

线程池 在编程中经常会使用线程来异步处理任务&#xff0c;但是每个线程的创建和销毁都需要一定的开销。如果每次执行一个任务都需要开一个新线程去执行&#xff0c;则这些线程的创建和销毁将消耗大量的资源。并且线程都是“各自为政”&#xff0c;很难对其进行控制&#xff0c…...

http://noi.openjudge.cn/——2.5基本算法之搜索——200:Solitaire

文章目录 题目宽搜代码总结 题目 总时间限制: 5000ms 单个测试点时间限制: 1000ms 内存限制: 65536kB 描述 Solitaire is a game played on a chessboard 8x8. The rows and columns of the chessboard are numbered from 1 to 8, from the top to the bottom and from left t…...

deep鼠标跟随插件

效果图 实现 首先打开深度系统终端&#xff0c;键入以下安装命令&#xff1a; sudo apt install oneko安装完成后&#xff0c;执行以下命令启动&#xff1a; oneko启动后&#xff0c;就会出现小猫咪&#xff0c;如果终端不关&#xff08;服务不关&#xff09;&#xff0c;会…...

Verilog 语法 (二)

在掌握了 Verilog 的基础语法和常用程序框架之后&#xff0c;本节将带大家深入学习一些 高级设计知识点。这些内容包括&#xff1a; 阻塞赋值&#xff08;&#xff09;与非阻塞赋值&#xff08;<&#xff09;的区别及使用场景&#xff1b; assign 和 always 语句的差异&am…...

大数据开发环境的安装,配置(Hadoop)

1. 三台linux服务器的安装 1. 安装VMware VMware虚拟机软件是一个“虚拟PC”软件&#xff0c;它使你可以在一台机器上同时运行二个或更多Windows、DOS、LINUX系统。与“多启动”系统相比&#xff0c;VMWare采用了完全不同的概念。 我们可以通过VMware来安装我们的linux虚拟机…...

唯创安全:从传统到智能,工厂智能叉车AI防撞系统解决方案

一、叉车安全管理现状痛点分析 1、司机管理难题 • 违规操作频发&#xff1a;无证驾驶、疲劳驾驶(如作业中吸烟/玩手机)及不系安全带现象普遍&#xff0c;事故风险与法律风险双高。 • 资源分配失衡&#xff1a;未经授权使用导致车辆调度混乱&#xff0c;影响作业效率。 2、…...

Windows与CasaOS跨平台文件同步:SyncThing本地部署与同步配置流程

文章目录 前言1. 添加镜像源2. 应用安装测试3. 安装syncthing3.1 更新应用中心3.2 SyncThing安装与配置3.3 Syncthing使用演示 4. 安装内网穿透工具5. 配置公网地址6. 配置固定公网地址 推荐 ​ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽…...

基于Django的个性化股票交易管理系统

本项目基于Python3.6、Django2.1、MySql8.0&#xff08;最好不要使用5.6&#xff0c;字符集等方面均不兼容&#xff0c;否则导入数据库会出错&#xff09;与股票信息工具包TuShare实现。 创建或激活对应Python开发环境 这里使用了conda来管理环境&#xff0c;强烈推荐&#xf…...

Python图像变清晰与锐化,调整对比度,高斯滤波除躁,卷积锐化,中值滤波钝化,神经网络变清晰

本次使用图片来源于百度 import cv2 import time import numpy as np import pywtfrom PIL import Image, ImageEnhance#-i https://pypi.mirrors.ustc.edu.cn/simpledef super_resolution(input_path, output_path, model_path, scale4):# 初始化超分辨率模型sr cv2.dnn_su…...

带根线就无敌?光纤无人机如何成为电子战的终结者

在硝烟弥漫的俄乌战场上&#xff0c;一条超细光缆正在悄然改变战争规则。2024年俄军首次在前线部署光纤FPV无人机&#xff0c;其通过释放光纤线缆传输数据&#xff0c;成功对乌军装甲目标实施精准打击。乌方同时也迅速跟进&#xff0c;于 2025 年初量产光纤FPV 无人机以突破俄军…...

windows 和ubuntu静态路由配置

目录 windows 1 查看当前路由表 2 添加静态路由 3 删除路由 ubuntu route命令&#xff08;传统方式&#xff09; 使用ip指令&#xff08;推荐&#xff09; ubuntu永久路由配置 子网掩码解释 windows 1 查看当前路由表 -4 只关注ipv4&#xff0c;-6 用于指定显示 IPv6 …...

《深入理解计算机系统》阅读笔记之第四章 处理器体系结构

概述 备注&#xff1a;怎么感觉讲的还是《编码》这本书里面提到的知识点&#xff1f;...

vue项目前后端分离设计

在Vue前端架构中&#xff0c;通过分层结构和模块化设计实现高效的前后端分离&#xff0c;需要系统性规划各层职责、接口管理和数据流控制。以下是结合业界最佳实践的完整方案&#xff1a; 一、分层架构设计 1. 分层结构&#xff08;自上而下&#xff09; 层级职责示例技术实现…...

Steam游戏服务器攻防全景解读——如何构建游戏级抗DDoS防御体系?

Steam游戏服务器的DDoS攻防体系设计&#xff0c;从协议层漏洞利用到业务连续性保障&#xff0c;深度拆解反射型攻击、TCP状态耗尽等7类威胁场景。基于全球15个游戏厂商攻防实战数据&#xff0c;提供包含边缘节点调度、AI流量指纹识别、SteamCMD加固配置的三维防护方案&#xff…...

七、web自动化测试03

目录 一、xpath定位1. 属性定位2.属性与逻辑结合3. 属性与层级结合 二、cookie1. 验证码处理方案2. cookie3. 案例&#xff1a;cookie跳过登录 三、pytest1. 介绍及安装2. 定义用例3. 执行测试用例3.1 命令行运行3.2 配置文件运行3.3 项目配置文件config.py 4. 参数化5. 断言6.…...

企业级AI开发利器:Spring AI框架深度解析与实战

企业级AI开发利器&#xff1a;Spring AI框架深度解析与实战 一、前言&#xff1a;Java生态的AI新纪元 在人工智能技术爆发式发展的今天&#xff0c;Java开发者面临着一个新的挑战&#xff1a;如何将大语言模型&#xff08;LLMs&#xff09;和生成式AI&#xff08;GenAI&#…...

docker-compose安装RustDesk远程工具

以下是使用 docker-compose 部署 RustDesk 服务端(ID服务器 hbbs + 中继服务器 hbbr)的完整流程: 1. 创建 docker-compose.yml mkdir -p ~/rustdesk && cd ~/rustdesk vi docker-compose.ymlversion: 3.8services...

Qt基础009(HTTP编程和QJSON)

文章目录 软件开发网络架构BS架构/CS架构 HTTP基本概念QT的HTTP编程JSON数据概述QT生成JSON数据QT解析JSON数据 软件开发网络架构 BS架构/CS架构 ​ 在计算机网络和软件开发中&#xff0c;CS架构&#xff08;Client-Server Architecture&#xff0c;客户端-服务器架构&#x…...

学习整理在centos7上安装mysql8.0版本教程

学习整理在centos7上安装mysql8.0版本教程 查看linux系统版本下载mysql数据库安装环境检查解压mysql安装包创建MySQL需要的目录及授权新增用户组新增组用户配置mysql环境变量编写MySQL配置文件初始化数据库初始化msyql服务启动mysql修改初始化密码配置Linux 系统服务工具,使My…...

第R4周:LSTM-火灾温度预测

文章目录 一、前期准备工作1.导入数据2. 数据集可视化 二、构建数据集1. 数据集预处理2. 设置X, y3. 划分数据集 三、模型训练1. 构建模型2. 定义训练函数3. 定义测试函数4. 正式训练模型 四、模型评估1. Loss图片2. 调用模型进行预测3. R2值评估 总结&#xff1a; &#x1f36…...

Linux文件管理完全指南:从命名规则到压缩解压

一、文件命名规则&#xff1a;避免踩坑的关键 1. 允许的字符与命名建议 允许字符&#xff1a;除 / 外所有字符均可使用&#xff0c;但需避免 <, >, ?, * 等特殊符号。 命名建议&#xff1a; 统一使用小写字母&#xff08;Linux严格区分大小写&#xff09;。 用下划线…...

react和vue的区别之一

前言 小编在学react的时候&#xff0c;发现react在使用ant-design组件的from表单&#xff0c;有点惊奇&#xff0c;跟vue差别确实有点大。 1-React 与 Vue 表单处理对比指南 核心差异概述 特性VueReact (Ant Design Form)数据定义必须显式定义 reactive/ref通过 name 隐式定…...

电力系统最小惯性常数解析

1. 什么是惯性常数&#xff1f; 电力系统的惯性常数&#xff08;Inertia Constant&#xff09;可以理解为系统抵抗频率突变的能力&#xff0c;类似于“惯性”。传统电力系统中&#xff0c;同步发电机&#xff08;如火电厂&#xff09;的旋转部件&#xff08;如涡轮、转子&…...

Linux软硬链接和动静态库(20)

文章目录 前言一、软硬链接基本认知实现原理应用场景取消链接ACM时间 二、动静态库认识库库的作用 三、制作静态库静态库的打包静态库的使用 四、制作动态库动态区的打包动态库的链接与使用动态库的链接原理 总结 前言 我有款非常喜欢玩的游戏&#xff0c;叫做《饥荒》&#xf…...

FX10(CYUSB4014)USB3.2(10Gbps)开发笔记分享(1):硬件设计与开发环境搭建

作者&#xff1a;Hello&#xff0c;Panda 大家早上好&#xff0c;中午好&#xff0c;下午好&#xff0c;晚上好&#xff0c;熊猫君又来了。这次计划做一个连载&#xff0c;大概6期左右&#xff0c;主要介绍英飞凌最新的FX5/10/20的器件应用。目前&#xff0c;熊猫君手上调试的…...