数据结构与算法分析:树与哈希表(一)
遇到的问题,都有解决方案,希望我的博客能为你提供一点帮助。
一、概述
背景:链表处理大量数据时,线性访问耗时多。二叉查找树多数操作平均运行时间为 O (log N),相对于链表树更加高效。
1.预备知识
1.1. 树的定义与基本概念
-
树(Tree): 非线性数据结构,由节点(Node)和边(Edge)组成,满足以下条件:
- 存在唯一根节点(Root),无父节点。
- 除根节点外,每个节点有且仅有一个父节点。
- 从根到任意节点有唯一路径,无环路。
-
关键术语:
- 根节点(Root):树的顶端节点,没有父节点。
-
子节点(Child):一个节点的直接下级节点。
-
父节点(Parent):一个节点的直接上级节点。
-
叶子节点(Leaf):没有子节点的节点。
-
内部节点(Internal Node):至少有一个子节点的节点。
-
子树(Subtree):一个节点及其所有后代节点构成的树。
-
边(Edge):连接两个节点的线段。
-
路径(Path):从某一节点到其子孙节点的连续边序列。
-
深度(Depth):根节点到该节点的路径长度(根节点深度为0)。
-
高度(Height):节点到最深叶子节点的路径长度(叶子节点高度为0)。
-
树的深度=树的高度
-
节点所在的层(level):从顶至底递增,根节点所在层为 1 。
- 节点的度(degree):节点的子节点的数量。在二叉树中,度的取值范围是 0、1、2 。
class TreeNode:def __init__(self, val, left=None, right=None):self.val = valself.left = leftself.right = rightdef plot_tree(root):"""可视化二叉树"""import matplotlib.pyplot as pltfrom matplotlib.patches import Circlefig, ax = plt.subplots(figsize=(10, 8))ax.set_aspect('equal')ax.axis('off')def get_height(node):if not node:return 0return 1 + max(get_height(node.left), get_height(node.right))tree_height = get_height(root)def plot_node(node, x, y, dx):if not node:return# 绘制当前节点circle = Circle((x, y), 0.3, fill=True, color='lightblue')ax.add_patch(circle)ax.text(x, y, str(node.val), ha='center', va='center', fontsize=12)# 绘制左子树if node.left:new_x = x - dxnew_y = y - 1ax.plot([x, new_x], [y-0.3, new_y+0.3], 'k-', lw=1.5)plot_node(node.left, new_x, new_y, dx/2)# 绘制右子树if node.right:new_x = x + dxnew_y = y - 1ax.plot([x, new_x], [y-0.3, new_y+0.3], 'k-', lw=1.5)plot_node(node.right, new_x, new_y, dx/2)plot_node(root, 0, tree_height-1, 2**(tree_height-2))plt.xlim(-2**(tree_height-1), 2**(tree_height-1))plt.ylim(-1, tree_height)plt.show()# 测试用例
if __name__ == "__main__":# 构建一个示例树# 1# / \# 2 3# / \# 4 5root = TreeNode(1)root.left = TreeNode(2)root.right = TreeNode(3)root.left.left = TreeNode(4)root.left.right = TreeNode(5)plot_tree(root)
1.2树的递归定义
递归定义是一种通过自我引用来描述数据结构或算法的方式。对于树这种分层结构,递归定义尤其自然,因为每个子树本身也是一棵树。递归定义包含两个关键部分:
- 基线条件(Base Case):定义最简单、不可再分的情况(通常是空树或叶子节点)。
- 递归条件(Recursive Case):通过组合更小的树来定义更大的树。
通用树的递归定义
一个树可以是:
- 空树(基线条件),或者一个根节点,连接若干个子树(递归条件),每个子树本身也是树。
数学表达:
T=∅或T=(v,{T1,T2,...,Tn})
- v:根节点的值
- {T1,T2,...,Tn}:子树集合
动态演示建树过程:
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import timeclass TreeNode:def __init__(self, val, left=None, right=None):self.val = valself.left = leftself.right = rightdef build_tree_recursively(values, index=0):"""递归构建二叉树:param values: 节点值列表:param index: 当前节点索引:return: 构建好的树节点"""if index >= len(values) or values[index] is None:return Nonenode = TreeNode(values[index])# 递归构建左子树node.left = build_tree_recursively(values, 2*index+1)# 递归构建右子树node.right = build_tree_recursively(values, 2*index+2)return nodedef visualize_recursive_build(root, values):"""可视化递归构建过程:param root: 树的根节点:param values: 节点值列表"""fig, ax = plt.subplots(figsize=(12, 8))ax.set_aspect('equal')ax.axis('off')# 计算树的高度def get_height(node):if not node:return 0return 1 + max(get_height(node.left), get_height(node.right))tree_height = get_height(root)# 存储节点高度信息node_heights = {}def calc_heights(node):if not node:return 0h = 1 + max(calc_heights(node.left), calc_heights(node.right))node_heights[id(node)] = h - 1return hcalc_heights(root)# 递归构建并可视化def recursive_build_visualize(node, x, y, dx, depth=0, is_new=False):if not node:return# 绘制当前节点color = 'red' if is_new else 'lightblue'circle = Circle((x, y), 0.35, fill=True, color=color, alpha=0.8)ax.add_patch(circle)# 显示节点信息node_info = f"值: {node.val}\n深度: {depth}\n高度: {node_heights.get(id(node), 0)}"ax.text(x, y, node_info, ha='center', va='center', fontsize=10, bbox=dict(facecolor='white', alpha=0.7))plt.pause(0.5) # 暂停0.5秒展示当前步骤# 递归构建左子树if 2*values.index(node.val)+1 < len(values) and values[2*values.index(node.val)+1] is not None:new_x = x - dxnew_y = y - 1.5ax.plot([x, new_x], [y-0.35, new_y+0.35], 'b-', lw=1.5, alpha=0.6)plt.pause(0.3) # 展示连接线left_val = values[2*values.index(node.val)+1]left_node = TreeNode(left_val)node.left = left_noderecursive_build_visualize(left_node, new_x, new_y, dx/2, depth+1, True)# 递归构建右子树if 2*values.index(node.val)+2 < len(values) and values[2*values.index(node.val)+2] is not None:new_x = x + dxnew_y = y - 1.5ax.plot([x, new_x], [y-0.35, new_y+0.35], 'r-', lw=1.5, alpha=0.6)plt.pause(0.3) # 展示连接线right_val = values[2*values.index(node.val)+2]right_node = TreeNode(right_val)node.right = right_noderecursive_build_visualize(right_node, new_x, new_y, dx/2, depth+1, True)# 开始可视化构建过程plt.title("递归构建二叉树过程 (红色:新添加节点)", pad=20)recursive_build_visualize(root, 0, tree_height-1, 2**(tree_height-2))plt.xlim(-2**(tree_height-1), 2**(tree_height-1))plt.ylim(-tree_height, tree_height)# 设置中文字体plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体显示中文plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题plt.show()# 示例使用
if __name__ == "__main__":# 定义节点值列表 (None表示空节点)values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]# 构建完整的树结构root = build_tree_recursively(values)# 可视化递归构建过程visualize_recursive_build(root, values)
演示视频可以在我的视频资源里看:20250330_101822-CSDN直播
2、二叉树(Binary Tree)
2.1. 定义
-
每个节点最多有两个子节点(左子节点和右子节点)。
-
结构示例:
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = right
二叉树的递归定义
一个二叉树可以是:
- 空树(基线条件),或者一个根节点,连接一个左子树和一个右子树(递归条件),每个子树本身也是二叉树。
数学表达:
或
2.2. 特殊二叉树类型
(1) 满二叉树(Full Binary Tree)
-
每个节点要么是叶子节点,要么恰好有两个子节点。
-
示例:
1/ \2 3/ \ / \4 5 6 7
(2) 完全二叉树(Complete Binary Tree)
-
除最后一层外,其他层节点全满,且最后一层节点尽量靠左排列。
-
示例:
1/ \2 3/ \ /4 5 6
(3) 二叉搜索树(BST, Binary Search Tree)
-
左子树所有节点值 < 根节点值 < 右子树所有节点值。
-
作用:支持高效查找、插入、删除(时间复杂度 O(log n))。
-
示例:
4/ \2 6/ \ / \1 3 5 7
2.3树的遍历法
1/ \2 3/ \ / \4 5 6 7
2.3.1. 深度优先遍历(DFS)
-
前序遍历(Preorder):根 → 左 → 右
示例:1 → 2 → 4 → 5 → 3 → 6 → 7
def preorder(root):if not root: return []return [root.val] + preorder(root.left) + preorder(root.right)
-
中序遍历(Inorder):左 → 根 → 右
BST 中序遍历结果有序。
示例:4 → 2 → 5 → 1 → 6 → 3 → 7
def inorder(root):if not root: return []return inorder(root.left) + [root.val] + inorder(root.right)
-
后序遍历(Postorder):左 → 右 → 根
示例:4 → 5 → 2 → 6 → 7 → 3 → 1
def postorder(root):if not root: return []return postorder(root.left) + postorder(root.right) + [root.val]
2.3.2. 广度优先遍历(BFS / 层序遍历)
-
按层次逐层访问节点。
-
示例:
1 → 2 → 3 → 4 → 5 → 6 → 7
from collections import deque def level_order(root):if not root: return []queue = deque([root])res = []while queue:node = queue.popleft()res.append(node.val)if node.left: queue.append(node.left)if node.right: queue.append(node.right)return res
完整代码示例:
class TreeNode:"""二叉树节点类属性:val: 节点值left: 左子节点right: 右子节点"""def __init__(self, val=0, left=None, right=None):"""初始化二叉树节点参数:val: 节点值,默认为0left: 左子节点,默认为Noneright: 右子节点,默认为None"""self.val = valself.left = leftself.right = rightdef preorder(root):"""前序遍历二叉树参数:root: 二叉树根节点返回:包含前序遍历结果的列表"""if not root: return []return [root.val] + preorder(root.left) + preorder(root.right)def inorder(root):"""中序遍历二叉树参数:root: 二叉树根节点返回:包含中序遍历结果的列表"""if not root: return []return inorder(root.left) + [root.val] + inorder(root.right)def postorder(root):"""后序遍历二叉树参数:root: 二叉树根节点返回:包含后序遍历结果的列表"""if not root: return []return postorder(root.left) + postorder(root.right) + [root.val]from collections import deque
def level_order(root):"""层序遍历二叉树参数:root: 二叉树根节点返回:包含层序遍历结果的列表"""if not root: return []queue = deque([root])res = []while queue:node = queue.popleft()res.append(node.val)if node.left: queue.append(node.left)if node.right: queue.append(node.right)return res# 示例用法
if __name__ == "__main__":# 构建示例树# 1# / \# 2 3# / \ / \# 4 5 6 7root = TreeNode(1)root.left = TreeNode(2)root.right = TreeNode(3)root.left.left = TreeNode(4)root.left.right = TreeNode(5)root.right.left = TreeNode(6)root.right.right = TreeNode(7)print("前序遍历:", preorder(root))print("中序遍历:", inorder(root))print("后序遍历:", postorder(root))print("层序遍历:", level_order(root))
C++简易版
#include <iostream>
#include <vector>
#include <queue>using namespace std;// 二叉树节点结构体
struct TreeNode {int val; // 节点存储的值TreeNode* left; // 指向左子节点的指针TreeNode* right; // 指向右子节点的指针// 构造函数// 参数x: 节点存储的整数值TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};// 前序遍历二叉树(根-左-右)
// 参数root: 二叉树的根节点
// 返回值: 包含前序遍历结果的整数向量
vector<int> preorder(TreeNode* root) {if (!root) return {}; // 空树返回空向量vector<int> result;result.push_back(root->val); // 访问根节点vector<int> left = preorder(root->left); // 递归遍历左子树vector<int> right = preorder(root->right); // 递归遍历右子树result.insert(result.end(), left.begin(), left.end()); // 合并左子树结果result.insert(result.end(), right.begin(), right.end()); // 合并右子树结果return result;
}// 中序遍历二叉树(左-根-右)
// 参数root: 二叉树的根节点
// 返回值: 包含中序遍历结果的整数向量
vector<int> inorder(TreeNode* root) {if (!root) return {}; // 空树返回空向量vector<int> left = inorder(root->left); // 递归遍历左子树vector<int> result;result.push_back(root->val); // 访问根节点vector<int> right = inorder(root->right); // 递归遍历右子树left.insert(left.end(), result.begin(), result.end()); // 合并根节点结果left.insert(left.end(), right.begin(), right.end()); // 合并右子树结果return left;
}// 后序遍历二叉树(左-右-根)
// 参数root: 二叉树的根节点
// 返回值: 包含后序遍历结果的整数向量
vector<int> postorder(TreeNode* root) {if (!root) return {}; // 空树返回空向量vector<int> left = postorder(root->left); // 递归遍历左子树vector<int> right = postorder(root->right); // 递归遍历右子树right.push_back(root->val); // 访问根节点left.insert(left.end(), right.begin(), right.end()); // 合并右子树和根节点结果return left;
}// 层序遍历二叉树(广度优先)
// 参数root: 二叉树的根节点
// 返回值: 包含层序遍历结果的整数向量
vector<int> levelOrder(TreeNode* root) {if (!root) return {}; // 空树返回空向量queue<TreeNode*> q; // 使用队列辅助遍历q.push(root); // 根节点入队vector<int> result;while (!q.empty()) {TreeNode* node = q.front(); // 取出队首节点q.pop();result.push_back(node->val); // 访问当前节点if (node->left) q.push(node->left); // 左子节点入队if (node->right) q.push(node->right); // 右子节点入队}return result;
}int main() {// 构建示例树// 1// / \// 2 3// / \ / \// 4 5 6 7// 这是一个完全二叉树,用于测试各种遍历方法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);root->right->left = new TreeNode(6);root->right->right = new TreeNode(7);cout << "前序遍历: ";for (int num : preorder(root)) {cout << num << " ";}cout << endl;cout << "中序遍历: ";for (int num : inorder(root)) {cout << num << " ";}cout << endl;cout << "后序遍历: ";for (int num : postorder(root)) {cout << num << " ";}cout << endl;cout << "层序遍历: ";for (int num : levelOrder(root)) {cout << num << " ";}cout << endl;// 释放内存delete root->right->right;delete root->right->left;delete root->left->right;delete root->left->left;delete root->right;delete root->left;delete root;return 0;
}
3.二叉树的数组表示
核心思想:用连续的内存空间(数组)存储二叉树节点,通过索引计算确定节点间的父子关系。
适用场景
-
完全二叉树:数组表示最紧凑,无空间浪费。
-
非完全二叉树:可能存在空间浪费,需用特殊值标记空节点。
3.1、数组存储规则
3.1.1. 索引分配规则(适用于完美二叉树)
假设数组从 索引0 开始存储:
-
根节点:索引为
0
。 -
父节点索引
i
:-
左子节点索引:
2*i + 1
-
右子节点索引:
2*i + 2
-
-
子节点索引
j
:-
父节点索引:
⌊(j-1)/2⌋
(向下取整)
-
2. 空节点标记(非完美二叉树)
-
用特定值(如
None
、null
或特殊符号)表示缺失的节点。
3.1.2、示例分析
示例1:完全二叉树的数组表示
-
树结构:
1/ \2 3/ \ / \4 5 6 7
-
数组表示:
[1, 2, 3, 4, 5, 6, 7]
-
索引关系:
-
根节点
1
的索引为0
。 -
左子节点
2
的索引为1
(2*0+1
)。 -
右子节点
3
的索引为2
(2*0+2
)。 -
节点
4
(索引3
)的父节点为1
(⌊(3-1)/2⌋=1
)。
-
-
示例2:非完全二叉树的数组表示
-
树结构:
1/ \2 3\ \5 7
-
数组表示(用
null
填充空缺):[1, 2, 3, null, 5, null, 7]
-
说明:
-
索引
3
(左子节点位置)为null
,表示节点2
无左子节点。 -
索引
5
(右子节点位置)为null
,表示节点3
无左子节点。
-
-
3.2、数组表示 vs. 链式表示
维度 | 数组表示 | 链式表示 |
---|---|---|
空间效率 | 完全二叉树高效;非完全二叉树可能浪费空间 | 灵活,无空间浪费 |
访问速度 | 直接通过索引计算,速度快 | 需遍历指针,速度较慢 |
插入/删除 | 需要移动元素,效率低 | 修改指针即可,效率高 |
适用场景 | 完全二叉树、堆 | 任意二叉树(尤其是非完全树) |
3.3、代码实现
3.3.1. 根据数组构建二叉树(链式结构)
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightdef build_tree(arr, i=0):if i >= len(arr) or arr[i] is None:return Noneroot = TreeNode(arr[i])root.left = build_tree(arr, 2*i + 1)root.right = build_tree(arr, 2*i + 2)return root# 示例:构建示例2的非完全二叉树
arr = [1, 2, 3, None, 5, None, 7]
root = build_tree(arr)
C++版
#include <vector>
#include <queue>
#include <iostream>
using namespace std;/*** @brief 二叉树节点结构* @param val 存储的数据元素* @param left 指向左子节点的指针* @param right 指向右子节点的指针* */
struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x = 0, TreeNode* l = nullptr, TreeNode* r = nullptr) : val(x), left(l), right(r) {}
};/*** @brief 根据数组构建二叉树* @param arr 包含二叉树节点值的数组,-1表示空节点* @param i 当前处理的数组索引,默认为0(根节点)* @return TreeNode* 构建完成的二叉树根节点* @note 使用完毕后需要调用deleteTree释放内存*/
TreeNode* buildTree(const vector<int>& arr, int i = 0) {// 参数校验if (arr.empty()) {return nullptr;}// 递归终止条件:索引越界或遇到空节点标记if (i < 0 || i >= arr.size() || arr[i] == -1) {return nullptr;}// 创建当前节点并递归构建左右子树TreeNode* root = new TreeNode(arr[i]);root->left = buildTree(arr, 2 * i + 1);root->right = buildTree(arr, 2 * i + 2);return root;
}/*** @brief 释放二叉树内存* @param root 二叉树根节点*/
void deleteTree(TreeNode* root) {if (!root) return;deleteTree(root->left);deleteTree(root->right);delete root;
}void printTree(TreeNode* root) {if (!root) {return; // 空节点,直接返回 }queue<TreeNode*> q; // 队列用于层次遍历 q.push(root); // 根节点入队while (!q.empty()) {TreeNode* curr = q.front();q.pop();cout << curr->val << " "; // 输出当前节点的值if (curr->left) {q.push(curr->left); // 左子节点入队} else {} // 空节点,不做处理if (curr->right) {q.push(curr->right); // 右子节点入队} else {} // 空节点,不做处理}
}/*** @brief 演示二叉树构建和删除*/
int main() {// 示例数组表示二叉树vector<int> treeData = {1, 2, 3, -1, 4, 5, 6, -1, -1, 7, 8};// 构建二叉树TreeNode* root = buildTree(treeData);// 这里可以添加遍历或其他操作cout << "Tree in level order: ";printTree(root);cout << endl << "Tree deleted." << endl;// 释放内存deleteTree(root);return 0;
3.3.2. 将二叉树转为数组表示
def tree_to_array(root):if not root:return []queue = [root]res = []while queue:node = queue.pop(0)if node:res.append(node.val)queue.append(node.left)queue.append(node.right)else:res.append(None)# 去除末尾的 None(可选)while res and res[-1] is None:res.pop()return res# 示例:将链式树转回数组
print(tree_to_array(root)) # 输出 [1, 2, 3, None, 5, None, 7]
c++版
#include <vector>
#include <queue>
#include <iostream>
#include <memory>
using namespace std;/*** @brief 二叉树节点结构* 使用智能指针管理内存,防止内存泄漏*/
struct TreeNode {int val;shared_ptr<TreeNode> left;shared_ptr<TreeNode> right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};/*** @brief 将二叉树转换为数组表示(层次遍历)* @param root 二叉树根节点* @return 包含节点值的vector,空节点用-1表示* @note 使用智能指针避免内存泄漏*/
vector<int> treeToArray(shared_ptr<TreeNode> root) {vector<int> result;if (!root) {return result;}queue<shared_ptr<TreeNode>> q;q.push(root);while (!q.empty()) {auto node = q.front();q.pop();if (node) {result.push_back(node->val);q.push(node->left);q.push(node->right);} else {result.push_back(-1); // 使用-1表示空节点}}// 去除末尾的-1(可选)while (!result.empty() && result.back() == -1) {result.pop_back();}return result;
}int main() {try {// 构建示例二叉树auto root = make_shared<TreeNode>(1);root->left = make_shared<TreeNode>(2);root->right = make_shared<TreeNode>(3);root->left->right = make_shared<TreeNode>(5);root->right->right = make_shared<TreeNode>(7);// 转换为数组并打印vector<int> arr = treeToArray(root);cout << "层次遍历结果: ";for (int val : arr) {cout << val << " ";}cout << endl;// 输出: 1 2 3 -1 5 -1 7 } catch (const exception& e) {cerr << "错误: " << e.what() << endl;return 1;}return 0;
}
相关文章:
数据结构与算法分析:树与哈希表(一)
遇到的问题,都有解决方案,希望我的博客能为你提供一点帮助。 一、概述 背景:链表处理大量数据时,线性访问耗时多。二叉查找树多数操作平均运行时间为 O (log N),相对于链表树更加高效。 1.预备知识 1.1. 树的定义与…...
VBA第三十四期 VBA中怎么用OnKey事件
我们在VBA设计中经常需要使用到OnKey方法,特别是在窗口设计中比如我们想用到翻页按键,则就可以来建立一个OnKey事件。Setup_OnKey过程运行以后,就会达到最终效果,按PgDn键会将指针下移一行,按PgUp键会将指针上移一行。…...
HarmonyOS NEXT开发进阶(十五):日志打印 hilog 与 console.log 的区别
文章目录 一、前言二、两者区别对比三、HiLog 详解四、拓展阅读 一、前言 在日常开发阶段,日志打印是调试程序非常常用的操作,在鸿蒙的官方文档中介绍了hilog这种方式,前端转过来的开发者发现console.log也可以进行日志打印,而且…...
Skynet 框架中 gateserver、gate、watchdog 的关系
一、概述 在 Skynet 框架的网络通信架构中,gateserver、gate、watchdog 是三个核心组件,共同实现客户端连接的监听、管理和业务逻辑的分发。其设计目标是通过分层解耦,提升网络层的稳定性与业务逻辑的灵活性。 二、组件职责 1. gateserve…...
第11章:优化I/O_《C++性能优化指南》_notes
第十一章核心知识点详解 11.1 读取文件的优化技巧 重点:减少内存分配、使用大缓冲区、优化函数调用链。 难点:理解系统调用开销与缓冲区大小的权衡。 代码示例与详解 示例1:使用高效函数签名和减少内存分配 #include <fstream> #inc…...
【C++初阶】--- 内存管理
1.C/C内存分布 我们一般说的32位机器和64位机器指的是虚拟空间的大小,也就是进程地址空间的大小,32位机器下,进程地址空间的大小是232个字节,也就是4G,64位机器下,进程地址空间的大小是264个字节,大概160亿…...
使用 Ansys Discovery 可视化液体池中的水流
了解 ANSYS Discovery:设计领域的变革者 ANSYS Discovery 是一款功能强大的软件工具,能够彻底改变设计流程。借助其先进的仿真功能,工程师现在可以在设计投入生产之前更深入地了解其设计。通过使用 ANSYS Discovery,设计师可以快…...
网络安全-网络安全基础
一、网络安全概述 TCP/IP协议定义了一个对等的开放性网络,使得连接到这个网络中的所有用户都可能面临来自网络中的恶意的破坏和攻击。这些攻击通过网络通信协议、网络应用协议甚至物理传输链路来实现。主要针对于软件和硬件进行攻击。那在互联网上如何保证自己的安…...
YOLOv8+ Deepsort+Pyqt5车速检测系统
该系统通过YOLOv8进行高效的目标检测与分割,结合DeepSORT算法完成目标的实时跟踪,并利用GPU加速技术提升处理速度。系统支持模块化设计,可导入其他权重文件以适应不同场景需求,同时提供自定义配置选项,如显示标签和保存…...
QML中的附加属性和附加信号处理程序
QML中的附加属性和附加信号处理程序 在QML中,附加属性(Attached Properties)和附加信号处理程序(Attached Signal Handlers)是特殊类型的属性和信号,它们由附加类型(Attached Types)提供,而不是由对象本身直接提供。 什么是附加的(Attached…...
爱普生FC-135晶振5G手机的极端温度性能守护者
在5G时代,智能手机不仅需要高速率与低延迟,更需在严寒、酷暑、振动等复杂环境中保持稳定运行。作为 5G 手机的核心时钟源,爱普生32.768kHz晶振FC-135凭借其宽温适应性、高精度稳定性与微型化设计,成为5G手机核心时钟源的理想选择&…...
GPT Workspace体验
GPT Workspace是一款将强大的自然语言处理模型(如 ChatGPT 和 Gemini)集成到 Google Workspace 应用(如 Google Docs, Sheets, Slides, Gmail 和 Drive)中的工具或插件。它的目标是提升用户在日常办公中的效率和创造力。 以下是对…...
Teleport 和 Set Actor location的区别
Teleport 和 Set Actor Location 都可以用于移动一个 Actor 的位置,但它们在底层逻辑和适用场景上有显著区别. 1. Set Actor Location 功能: 直接设置 Actor 的位置,不重置物理状态(如速度、动量)。 行为特点…...
“GPU 挤不动了?”——聊聊基于 GPU 的计算资源管理
“GPU 挤不动了?”——聊聊基于 GPU 的计算资源管理 作者:Echo_Wish “老板:为什么 GPU 服务器卡得跟 PPT 一样?” “运维:我们任务队列爆炸了,得优化资源管理!” 在 AI 训练、深度学习、科学计算的场景下,GPU 计算资源已经成为香饽饽。但 GPU 服务器贵得离谱,一台 A…...
解决前端项目中无法识别 .node 文件的依赖安装问题
解决前端项目中无法识别 .node 文件的依赖安装问题 问题描述 在 macOS 系统(M1 Pro 芯片),使用 Node.js 版本 20.9.0 和 Vue 3 的环境下,项目启动过程中遇到了以下错误: [ERROR] No loader is configured for "…...
Gateway实战入门(四)、断言-请求头以及请求权重分流等
spring cloud-Gateway:断言-请求头以及请求权重分流等 一、断言Header信息要求项目前置环境要求案例一、断言-请求头信息-匹配X-Request-Id1、配置文件及代码2、测试 案例二、断言-请求头信息-匹配API版本场景主要配置信息 案例三、断言-请求头信息:匹配…...
YOLOv11模型的常见处理
一.数据准备: 1.数据集格式: 目录结构示例: datasets/├── images/│ ├── train/ # 训练图片│ └── val/ # 验证图片└── labels/├── train/ # 训练标签└── val/ # 验证标签 每张图片对应一个 .txt 标注文件…...
conda 清除 tarballs 减少磁盘占用 、 conda rename 重命名环境、conda create -n qwen --clone 当前环境
🥇 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 🎉 声明: 作为全网 AI 领域 干货最多的博主之一,❤️ 不负光阴不负卿 ❤️ 文章目录 conda clean --tarballsconda rename 重命名环境conda create -n qwen --clone …...
无线局域网
1.5G支持中低频和高频频段, 2.网络切片是指从应该网络中选取特定的特性和功能 3.WLAN广义指无线电波,激光,红外线等无线信号代替有线局域网中的部分或者全部传输介质所构成的网络。 4.802.11运行在2.4GHz ISM 频段,采用扩频通信…...
百人会上的蔚小理与「来的刚刚好」的雷军
这就是2025百人会上的蔚小理,努力的李斌、宣扬飞行汽车的何小鹏与大讲开源的李想。那么小米汽车的模式是什么呢?站在蔚小理的肩上。 这就是2025百人会上的蔚小理,努力的李斌、宣扬飞行汽车的何小鹏与大讲开源的李想。那么小米汽车的模式是什么…...
现代优雅杂志海报徽标设计手写英文字体安装包 Attomes – Brush Handwritten Font
Attomes 简介 – Brush 手写字体 此字体是一种精致、优雅、流畅的手写字体。它有一个美丽而独特的连字混合字母,因此作者用一个小漩涡嵌入来撰写它,从而形成现代字体,并准备好通过为您的下一个设计项目添加优雅和独特的风格来发表声明。将其…...
Java进阶——静态代理与动态代理
代理模式是一种常用的设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理模式就像是一个中间人,客户端通过代理来间接访问目标对象,可以在不修改目标对象的基础上,对目标对象的功能进行增强或扩展。代理模式主要分为静…...
【多线程】进阶
目录 一、CAS 什么是 CAS CAS 伪代码 CAS 有哪些应用 实现原子类 CAS 是怎么实现的 如何通过 CAS 实现的原子类 CAS 的 ABA 问题 什么是 ABA 问题 ABA 问题引来的 BUG 正常的过程 异常的过程 解决方案 📝相关面试题 二、JUC(java.util.concurrent)的…...
MFC中字符串string类型和CString类型互转方法
文章目录 一、CString 转 std::string1. Unicode项目(_UNICODE 已定义)2. 多字节项目(_MBCS 已定义) 二、std::string 转 CString1. Unicode项目(_UNICODE 已定义)2. 多字节项目(_MBCS 已定义&a…...
工作记录 2017-03-13
工作记录 2017-03-13 序号 工作 相关人员 1 修改邮件上的问题。 开始处理操作日志部分。 测试了C#和MySql的连接。 更新RD服务器。 郝 更新的问题 1、 修改了CMS1500的打印,NDC的内容用了小的字体。 2、在Cliams List中可以查看Job的Notes。 3、Payment Po…...
Linux 配置NFS服务器
1. 开放/nfs/shared目录,供所有用户查阅资料 服务端 (1)安装nfs服务,nfs-utils包中包含rpcbind(rpc守护进程) [rootnode1-server ~]# yum install -y nfs-utils # nfs-utils包中包含rpcbind [rootnode…...
Linux《进程概念(上)》
在之前的Linux学习当中我们已经了解了基本的Linux指令以及基础的开发工具的使用,那么接下来我们就要开始Linux当中一个非常重要的部分的学习——进程,在此进程是我们之后Linux学习的基础,并且通过进程的学习会让我们了解更多的操作系统的相关…...
游戏开发中的贝塞尔曲线:感受丝滑的数学之美
这是一篇vip文章,如果你还不是vip,可以移步https://www.ilikexff.cn/articles/165免费阅读。 介绍 贝塞尔曲线是计算机图形学中最重要的概念之一,以其在表示曲线时的灵活性和精确性而闻名。广泛应用于计算机图形学、动画、路径规划等领域的数学曲线。 贝塞尔曲线的数学原理基…...
Java【多线程】(6)定时器
目录 1.前言 2.正文 2.1库中定时器 2.2手搓定时器 3.小结 1.前言 哈喽大家好呀,今天继续给大家分享Java中定时器的学习,正文包括定时器的三种实现方式,正文如下。 2.正文 在 Java 中,定时器(Timer)…...
Epub转PDF软件Calibre电子书管理软件
Epub转PDF软件:Calibre电子书管理软件 一款好用的电子书管理软件,可快速导入电脑里的电子书并进行管理,支持多种格式,阅读起来非常方便。同时也有电子书格式转换功能。 第一步:添加电子书 将需要转换的电子书添加到…...
使用FastExcel时的单个和批量插入的问题
在我们用excel表进行插入导出的时候,通常使用easyexcel或者FastExcel,而fastexcel是easy的升级版本,今天我们就对使用FastExcel时往数据库插入数据的业务场景做出一个详细的剖析 场景1 现在我们数据库有一张组织表,组织表的字段…...
nginx https配置
一.https配置 HTTPS 协议是由HTTP 加上TLS/SSL 协议构建的可进行加密传输、身份认证的网络协议,主要通过数字证书、加密算法、非对称密钥等技术完成互联网数据传输加密,实现互联网传输安全保护。 1.生成证书 openssl genrsa -des3 -out server.key 20…...
git --- cherry pick
git --- cherry pick cherry pick cherry pick Cherry Pick 是 Git 中的一个操作,它允许你选择某个分支的某次(或多次)提交,并将其应用到当前分支,而不会合并整个分支的所有更改。 cherry pick 的作用 只提取某个特定的…...
虚拟机安装linux系统无法上网的解决方法
在虚拟环境中运行Linux系统时,有时会遇到网络连接问题,特别是在使用虚拟机软件如VMware或VirtualBox时。本文将详细介绍一种针对“虚拟机安装Linux系统无法上网”问题的解决方案,以CentOS 6.5为例,适用于其他基于NAT模式的虚拟机环…...
北大人工智能研究院朱松纯:“中国的AI叙事” 存在认知偏差
3月29日,在2025中关村论坛通用人工智能论坛上,北京通用人工智能学院院长,北京大学人工智能研究院、智能学院院长朱松纯表示,目前,行业对AI的讨论几乎被大模型能力所占据,而基础学科、原始创新与智能本质的研…...
Java高频面试之集合-20
hello啊,各位观众姥爷们!!!本baby今天来报道了!哈哈哈哈哈嗝🐶 面试官:讲讲 HashSet 的底层实现? HashSet 是 Java 集合框架中用于存储唯一元素的高效数据结构,其底层实…...
使用Qemu模拟32位ARM系统
一、环境 实验环境如下: 主机:x86_64 操作系统:Ubuntu 20.04.6 LTS Qemu版本:QEMU emulator version 4.2.1 Linux内核版本:linux-4.4.240 Busybox版本:busybox-1.35.0二、前置准备 下载 linux-4.4.240 源…...
【初阶数据结构】栈
文章目录 一、概念与结构 二、栈的实现 栈的定义 1.初始化 2.入栈 3.判断栈是否为空 4.出栈 5.取栈顶元素 6.获取栈中有效元素个数 2.销毁 三、完整码源 总结 一、概念与结构 栈: 一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据…...
docker-compose部署prometheus+grafana+node_exporter
目录 docker-compose文件 配置文件 文件层级关系,docker-compose和配置文件位于同级目录 node_exporter页面json文件 涉及离线包 一.docker-compose文件 [rootsulibao prometheus]# cat docker-compose.yml version: 3services:prometheus:image: registry.c…...
maya调整全局关节显示大小
请按以下步骤操作: 在 Maya 主菜单栏中,找到 Display (显示) 菜单。 在 Display 菜单下,找到 Animation (动画) 子菜单。 在 Animation 子菜单中,点击 Joint Size... (关节大小...)。 这时会弹出一个小窗口或者直接在界面上出现…...
“屏幕“的实现_程序中如何将数据映射到硬件_C++实战
前言 程序里的数据,最后都需要将数据对象写入硬件.C/C最大的优势体现也是在这里,他既是高级语言方便被程序员使用,又能和硬件沟通. 引入 以"屏幕"的实现,总结数据映射到硬件的代码写法 分析 软件部分 1.屏幕是数据对象---一切都是数据,一切都是对象;数据有类型,屏…...
R --- Error in library(***) : there is no package called ‘***’ (服务器非root用户)
步骤 步骤一:在自己目录下创建R包安装路径步骤二:配置用户本地的R库路径步骤三:安装缺失的包(在终端)步骤四:验证安装 步骤一:在自己目录下创建R包安装路径 mkdir -p ~/R_libs步骤二࿱…...
Go中的逃逸分析
什么是逃逸? 逃逸是指一个变量本来应该分配在栈(stack)上,但由于某些原因,最终被分配到了堆(heap)上。 类比: 栈就像一个临时的快餐盒,用来存放短期使用的数据。堆就像…...
解决 Android AGP 最新版本中 BuildConfig 报错问题
在最新版本的 Android Gradle Plugin (AGP) 中,Google 对构建系统做了不少改动,可能会导致一些与 BuildConfig 相关的问题。以下是常见问题及解决方案: 常见问题及修复方法 1. BuildConfig 类完全缺失 原因:AGP 8.0 默认不再为库模…...
Rollup系列之安装和入门
Rollup Rollup.js的主要用途是将小的代码片段编译成更大、更复杂的代码,例如库或应用程序。它特别适用于将ES模块编译成不同的模块形式,如AMD、CommonJS、UMD等,以便在不同的环境中使用。 Rollup的应用场景与好处: 插件或…...
Kafka 4.0 发布:KRaft 替代 Zookeeper、新一代重平衡协议、点对点消息模型、移除旧协议 API
KRaft 全面替代 ZooKeeper Apache Kafka 4.0 是一个重要的里程碑,标志着第一个完全无需 Apache ZooKeeper 运行的主要版本。 通过默认运行在 KRaft 模式下,Kafka 简化了部署和管理,消除了维护单独 ZooKeeper 集群的复杂性。 这一变化显著降…...
MQTT之重复消息(6、在项目中遇到的问题)
项目背景: 在 Spring Boot MQTT 5.0 环境中,RTU设备向SpringBoot平台发送心跳数据、业务监控数据。同时SpringBoot平台可以向RTU设备下发指令,RTU在执行完指令之后向平台发送响应数据。 问题一、SpingBoot平台发送指令给RTU设备,RTU设备能够…...
8、linux c 信号机制
一、信号概述 1. 信号概念 信号是一种在软件层次上对中断机制的模拟,是一种异步通信方式。信号的产生和处理都由操作系统内核完成,用于在进程之间传递信息或通知某些事件的发生。 2. 信号的产生 信号可以通过以下方式产生: 按键产生&…...
Set,Map,WakeSet,WakeMap
简介 Set、Map、WeakMap 和 WeakSet 是 ES6 引入的高级数据结构,它们的底层实现和特性与传统的对象和数组有显著差异 强弱引用了解: link Set Set对象 是一种用于存储 唯一值 的可迭代集合,可存储任意类型的值(原始值、对象引用等&…...
NSSCTF(MISC)—[HITCTF 2021]PNG
相应的做题地址:https://www.nssctf.cn/problem/819 import zlib from Crypto.Cipher import AES import base64 def decode(data, key, iv): cipher AES.new(key, AES.MODE_CBC, iv) decryptByts base64.b64decode(data) msg cipher.decrypt(decryptByts) msgs…...