C++进阶——封装红黑树实现map和set
目录
1、源码及框架分析
2、模拟实现map和set
2.1 复用的红黑树框架及Insert
2.2 iterator的实现
2.2.1 iterator的核心源码
2.2.2 iterator的实现思路
2.3 map支持[ ]
2.4 map和set的代码实现
2.4.1 MyMap.h
2.4.2 MySet.h
2.4.3 RBTree.h
2.4.4 Test.cpp
1、源码及框架分析
SGI-STL30版本源代码,map和set的源代码在map/set/stl_map.h/stl_set.h/stl_tree.h等几个头文件中。 map和set的实现结构框架核心部分截取出来如下:
// set
#ifndef __SGI_STL_INTERNAL_TREE_H
#include <stl_tree.h>
#endif
#include <stl_set.h>
#include <stl_multiset.h>// map
#ifndef __SGI_STL_INTERNAL_TREE_H
#include <stl_tree.h>
#endif
#include <stl_map.h>
#include <stl_multimap.h>// stl_set.h
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:// typedefs:typedef Key key_type;typedef Key value_type;private:typedef rb_tree<key_type, value_type,identity<value_type>, key_compare, Alloc> rep_type;rep_type t; // red-black tree representing set
};// stl_map.h
template <class Key, class T, class Compare = less<Key>,class Alloc = alloc>
class map {
public:// typedefs:typedef Key key_type;typedef T mapped_type;typedef pair<const Key, T> value_type;private:typedef rb_tree<key_type, value_type,select1st<value_type>, key_compare, Alloc> rep_type;rep_type t; // red-black tree representing map
};// stl_tree.h
struct __rb_tree_node_base {typedef __rb_tree_color_type color_type;typedef __rb_tree_node_base* base_ptr;color_type color;base_ptr parent;base_ptr left;base_ptr right;
};// stl_tree.h
template <class Key, class Value, class KeyOfValue, class Compare,class Alloc = alloc>
class rb_tree {
protected:typedef void* void_pointer;typedef __rb_tree_node_base* base_ptr;typedef __rb_tree_node<Value> rb_tree_node;typedef rb_tree_node* link_type;typedef Key key_type;typedef Value value_type;public:// insertpair<iterator, bool> insert_unique(const value_type& x);// erase and findsize_type erase(const key_type& x);iterator find(const key_type& x);protected:size_type node_count; // keeps track of size of treelink_type header;
};template <class Value>
struct __rb_tree_node : public __rb_tree_node_base {typedef __rb_tree_node<Value>* link_type;Value value_field;
};

template <class Key, class Value, class KeyOfValue, class Compare,class Alloc = alloc>
删除查找用Key,插入用Value,KeyOfValue如果是一个仿函数,取Value中的Key。
2、模拟实现map和set
2.1 复用的红黑树框架及Insert
1. 这里相比源码调整一下,key参数就用K,value参数就用V,红黑树中的数据类型,我们使用T。
2. 源码中的pair的<比较,比较了key和value,但是红黑树只需要比较key,所以MyMap和MySet各自实现了一个只比较key的仿函数。MySet是为了兼容MyMap,所以也要实现。
3. const保证了不能修改key。
RBTree<K, pair<const K, V>, MapKfromT> _t;
RBTree<K, const K, SetKfromT> _t;
template<class K, class T, class KfromT>
class RBTree{};
// 源码中 pair 支持的 < 重载
//template <class T1, class T2>
//bool operator<(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs) {
// return lhs.first < rhs.first || (!(rhs.first < lhs.first) && lhs.second < rhs.second);
//}// Mymap.h
namespace Lzc
{template<class K, class V>class MyMap{struct MapKfromT{const K& operator()(const pair<const K, V>& kv){return kv.first;}};public:bool insert(const pair<const K, V>& kv){return _t.Insert(kv);}private:RBTree<K, pair<const K, V>, MapKfromT> _t;};
}// Myset.h
namespace Lzc
{template<class K>class MySet{struct SetKfromT{const K& operator()(const K& k){return k;}};public:bool insert(const K& k){return _t.Insert(k);}private:RBTree<K, const K, SetKfromT> _t;};
}// RBTree.h
namespace Lzc
{enum Color{RED,BLACK};template<class T>struct RBTreeNode{T _data;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Color _col;RBTreeNode(const T& data):_data(data), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){ }};template<class K, class T, class KfromT>class RBTree{typedef RBTreeNode<T> Node;public:KfromT KfT;bool Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (KfT(data) > KfT(cur->_data)){parent = cur;cur = cur->_right;}else if (KfT(data) < KfT(cur->_data)){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(data);if (KfT(data) > KfT(parent->_data))parent->_right = cur;elseparent->_left = cur;cur->_parent = parent;while (parent && parent->_col == RED){Node* grandfather = parent->_parent;Node* uncle;if (parent == grandfather->_left){// g// p uuncle = grandfather->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_left){RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else{// g// u puncle = grandfather->_left;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}if (parent == nullptr)_root->_col = BLACK;return true;}void RotateR(Node* parent){Node* pParent = parent->_parent;Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;subL->_right = parent;parent->_parent = subL;subL->_parent = pParent;if (pParent == nullptr) // 当pParent == nullptr时,_root == parent{_root = subL;}else{if (pParent->_left == parent)pParent->_left = subL;elsepParent->_right = subL;}}void RotateL(Node* parent){Node* pParent = parent->_parent;Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;subR->_left = parent;parent->_parent = subR;subR->_parent = pParent;if (pParent == nullptr)_root = subR;else{if (pParent->_left == parent)pParent->_left = subR;elsepParent->_right = subR;}}Node* Find(const K& key){Node* cur = _root;while (cur){if (key > KfT(cur->_data))cur = cur->_right;else if (key < KfT(cur->_data))cur = cur->_left;elsereturn cur;}return nullptr;}~RBTree(){Destroy(_root);_root = nullptr;}void Destroy(Node* root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}private:Node* _root = nullptr;};
}
2.2 iterator的实现
2.2.1 iterator的核心源码
typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false;
const __rb_tree_color_type __rb_tree_black = true;struct __rb_tree_base_iterator {typedef __rb_tree_node_base::base_ptr base_ptr;base_ptr node;void increment() {if (node->right != 0) {node = node->right;while (node->left != 0)node = node->left;} else {base_ptr y = node->parent;while (node == y->right) {node = y;y = y->parent;}if (node->right != y)node = y;}}void decrement() {if (node->color == __rb_tree_red && node->parent->parent == node) {node = node->right;} else if (node->left != 0) {base_ptr y = node->left;while (y->right != 0)y = y->right;node = y;} else {base_ptr y = node->parent;while (node == y->left) {node = y;y = y->parent;}node = y;}}
};template <class Value, class Ref, class Ptr>
struct __rb_tree_iterator : public __rb_tree_base_iterator {typedef Value value_type;typedef Ref reference;typedef Ptr pointer;typedef __rb_tree_iterator<Value, Value&, Value*> iterator;__rb_tree_iterator() {}__rb_tree_iterator(link_type x) { node = x; }__rb_tree_iterator(const iterator& it) { node = it.node; }reference operator*() const { return link_type(node)->value_field; }#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */self& operator++() {increment();return *this;}self& operator--() {decrement();return *this;}inline bool operator==(const __rb_tree_base_iterator& x, const __rb_tree_base_iterator& y) {return x.node == y.node;}inline bool operator!=(const __rb_tree_base_iterator& x, const __rb_tree_base_iterator& y) {return x.node != y.node;}
};
2.2.2 iterator的实现思路
1. 整体思路与list的iterator一致,封装节点的指针,迭代器类模板多传Ref和Ptr两个参数,一份模板实现iterator和const_iterator。
2. 重点是operator++和operator--的实现。operator++走中序遍历,左中右,
当左为空,表示左访问完了,访问中(其实只能访问中,给的节点就是访问完的中节点),
如果右不为空,在右子树中进行,左中右,访问右子树的最左节点,
如果右为空(整个子树已经访问完了,如果这个子树是外面的右子树,那么外面一层的子树也访问完了,直到子树是外面子树的左子树,左子树访问完了,访问中),就访问,当孩子是父亲左的那个父亲(祖先),相当于外层左边的子树访问完了,然后访问中。
然后更新迭代器中的节点指针,返回*this。
operator--就是走右中左,基本相同。
3. begin和end。begin就给最左节点,end给nullptr,但是,--end()呢?
所以给迭代器类模板的增加一个成员变量_root(红黑树的根节点),--end()就可以是最右节点。
2.3 map支持[ ]
map要支持[ ]主要需要修改insert返回值,
修改RBtree中的insert返回值为pair<Iterator,bool> Insert(const T& data),
插入失败,就返回相同的key的value的引用。
插入成功,就返回key的value(默认值)的引用。
2.4 map和set的代码实现
2.4.1 MyMap.h
#pragma once
#include "RBTree.h"namespace Lzc
{template<class K, class V>class MyMap{struct MapKfromT{const K& operator()(const pair<const K, V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<const K, V>, MapKfromT>::Iterator iterator;typedef typename RBTree<K, pair<const K, V>, MapKfromT>::ConstIterator const_iterator;pair<iterator, bool> insert(const pair<const K, V>& kv){return _t.Insert(kv);}V& operator[](const K& k){iterator ret = _t.Insert({ k, V() }).first;return ret->second;}iterator begin(){return _t.Begin();}iterator end(){return _t.End();}const_iterator begin() const{return _t.Begin();}const_iterator end() const{return _t.End();}private:RBTree<K, pair<const K, V>, MapKfromT> _t;};
}
2.4.2 MySet.h
#pragma once#include "RBTree.h"namespace Lzc
{template<class K>class MySet{struct SetKfromT{const K& operator()(const K& k){return k;}};public:typedef typename RBTree<K, const K, SetKfromT>::Iterator iterator;typedef typename RBTree<K, const K, SetKfromT>::ConstIterator const_iterator;pair<iterator, bool> insert(const K& k){return _t.Insert(k);}iterator begin(){return _t.Begin();}iterator end(){return _t.End();}const_iterator begin() const{return _t.Begin();}const_iterator end() const{return _t.End();}private:RBTree<K, const K, SetKfromT> _t;};
}
2.4.3 RBTree.h
#pragma once#include <iostream>
#include <assert.h>using namespace std;namespace Lzc
{enum Color{RED,BLACK};template<class T>struct RBTreeNode{T _data;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Color _col;RBTreeNode(const T& data):_data(data), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){ }};template<class T, class Ref, class Ptr>struct RBTreeIterator{typedef RBTreeNode<T> Node;typedef RBTreeIterator<T, Ref, Ptr> Self;Node* _node;Node* _root;RBTreeIterator(Node* node, Node* root):_node(node), _root(root){}Self& operator++(){if (_node->_right){Node* cur = _node->_right;while (cur->_left){cur = cur->_left;}_node = cur;}else{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_right){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Self& operator--(){// --end,因为end == nullptr,所以最右节点需要_rootif (_node == nullptr){Node* MostRight = _root;while (MostRight->_right){MostRight = MostRight->_right;}_node = MostRight;}else if (_node->_left){Node* cur = _node->_left;while (cur->_right){cur = cur->_right;}_node = cur;}else{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &(_node->_data);}bool operator!=(const Self& s) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}};template<class K, class T, class KfromT>class RBTree{typedef RBTreeNode<T> Node;public:typedef RBTreeIterator<T, T&, T*> Iterator;typedef RBTreeIterator<T, const T&, const T*> ConstIterator;Iterator Begin(){Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return { cur,_root };}Iterator End(){return { nullptr,_root };}ConstIterator Begin() const{Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return { cur,_root };}ConstIterator End() const{return { nullptr,_root };}KfromT KfT;pair<Iterator, bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return { Iterator(_root,_root),true };}Node* parent = nullptr;Node* cur = _root;while (cur){if (KfT(data) > KfT(cur->_data)){parent = cur;cur = cur->_right;}else if (KfT(data) < KfT(cur->_data)){parent = cur;cur = cur->_left;}else{return { Iterator(cur,_root),false };}}cur = new Node(data);Node* newnode = cur; // cur可能后面会更新if (KfT(data) > KfT(parent->_data))parent->_right = cur;elseparent->_left = cur;cur->_parent = parent;while (parent && parent->_col == RED){Node* grandfather = parent->_parent;Node* uncle;if (parent == grandfather->_left){// g// p uuncle = grandfather->_right;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_left){RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else{// g// u puncle = grandfather->_left;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}if (parent == nullptr)_root->_col = BLACK;return { Iterator(newnode,_root),true };}void RotateR(Node* parent){Node* pParent = parent->_parent;Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;subL->_right = parent;parent->_parent = subL;subL->_parent = pParent;if (pParent == nullptr) // 当pParent == nullptr时,_root == parent{_root = subL;}else{if (pParent->_left == parent)pParent->_left = subL;elsepParent->_right = subL;}}void RotateL(Node* parent){Node* pParent = parent->_parent;Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;subR->_left = parent;parent->_parent = subR;subR->_parent = pParent;if (pParent == nullptr)_root = subR;else{if (pParent->_left == parent)pParent->_left = subR;elsepParent->_right = subR;}}Node* Find(const K& key){Node* cur = _root;while (cur){if (key > KfT(cur->_data))cur = cur->_right;else if (key < KfT(cur->_data))cur = cur->_left;elsereturn cur;}return nullptr;}~RBTree(){Destroy(_root);_root = nullptr;}void Destroy(Node* root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}private:Node* _root = nullptr;};
}
2.4.4 Test.cpp
#include "MySet.h"
#include "MyMap.h"// 遍历 MyMap
void TestMapIterator()
{Lzc::MyMap<int, string> map;map.insert({ 1, "one" });map.insert({ 2, "two" });map.insert({ 3, "three" });cout << "Testing MyMap iterator:" << endl;for (auto it = map.begin(); it != map.end(); ++it){cout << "Key: " << it->first << ", Value: " << it->second << endl;}cout << "-----------------------------" << endl;
}// 反向遍历 MyMap
void TestMapReverseIterator()
{Lzc::MyMap<int, string> map;map.insert({ 5, "five" });map.insert({ 3, "three" });map.insert({ 7, "seven" });auto it = map.end();--it; // 移动到最后一个元素cout << "Testing MyMap reverse iterator:" << endl;while (it != map.begin()){cout << "Key: " << it->first << ", Value: " << it->second << endl;--it;}cout << "Key: " << it->first << ", Value: " << it->second << endl; // 打印第一个元素cout << "-----------------------------" << endl;
}// 测试 operator[] 和迭代器
void TestMapOperatorBracket()
{Lzc::MyMap<int, string> map;map[1] = "one";map[2] = "two";map[3] = "three";cout << "Testing MyMap operator[] and iterator:" << endl;for (auto it = map.begin(); it != map.end(); ++it){cout << "Key: " << it->first << ", Value: " << it->second << endl;}cout << "-----------------------------" << endl;
}// 遍历 MySet
void TestSetIterator()
{Lzc::MySet<int> set;set.insert(10);set.insert(20);set.insert(30);cout << "Testing MySet iterator:" << endl;for (auto it = set.begin(); it != set.end(); ++it){cout << "Key: " << *it << endl;}cout << "-----------------------------" << endl;
}// 反向遍历 MySet
void TestSetReverseIterator()
{Lzc::MySet<int> set;set.insert(50);set.insert(30);set.insert(70);auto it = set.end();--it; // 移动到最后一个元素cout << "Testing MySet reverse iterator:" << endl;while (it != set.begin()){cout << "Key: " << *it << endl;--it;}cout << "Key: " << *it << endl; // 打印第一个元素cout << "-----------------------------" << endl;
}// 测试空 MySet 的迭代器
void TestEmptySetIterator()
{Lzc::MySet<int> set;auto it = set.begin();auto end = set.end();cout << "Testing empty MySet iterator:" << endl;if (it == end){cout << "Set is empty, begin() == end()" << endl;}else{cout << "Set is not empty" << endl;}cout << "-----------------------------" << endl;
}void RunIteratorTests()
{TestMapIterator();TestMapReverseIterator();TestMapOperatorBracket();TestSetIterator();TestSetReverseIterator();TestEmptySetIterator();
}int main()
{RunIteratorTests();return 0;
}相关文章:
C++进阶——封装红黑树实现map和set
目录 1、源码及框架分析 2、模拟实现map和set 2.1 复用的红黑树框架及Insert 2.2 iterator的实现 2.2.1 iterator的核心源码 2.2.2 iterator的实现思路 2.3 map支持[ ] 2.4 map和set的代码实现 2.4.1 MyMap.h 2.4.2 MySet.h 2.4.3 RBTree.h 2.4.4 Test.cpp 1、源码及…...
python基础-02-列表+序列数据类型
文章目录 【README】【4】python列表【4.1】列表数据类型【4.1.1】用索引取得列表中的单个值【4.1.2】负数索引【4.1.3】利用切片获取子列表【4.1.4】用索引改变列表中的值【4.1.5】列表连接与复制【4.1.6】del语句删除列表中的元素 【4.2】使用列表【4.2.1】列表用于循环【补充…...
‘闭包‘, ‘装饰器‘及其应用场景
‘闭包’, 装饰器’及其应用场景 一, 闭包及其应用场景 图解 闭包的定义 概述: 内部函数 使用了 外部函数 的变量, 这种写法就称之为闭包. 格式: def 外部函数名(形参列表):外部函数的(局部)变量def 内部函数名(形参列表):内部函数的(局部)变量return 内部函数名前提条件: …...
IDEA 快捷键ctrl+shift+f 无法全局搜索内容的问题及解决办法
本篇文章主要讲解IDEA、phpStrom、webStrom、pyCharm等jetbrains系列编辑器无法进行全局搜索内容问题的主要原因及解决办法。 日期:2025年3月22日 作者:任聪聪 现象描述: 1.按下ctrlshiftf 输入法转为了繁体。 2.快捷键ctrlshiftr 可以全局检…...
Java——Random库
一、作用 Random库——生成随机数 二、实现步骤 1.导包:import java.util.Random; #快捷键:“Random”回车键 2.取得随机数:Random 变量1 new Random(); 3.调用随机数:类型 变量2 变量1.nextInt(n); (代表变量…...
【通过Groovy去热修复线上逻辑】1.执行线上数据修复 2.写工具
1.执行groovy // 实际执行的话, 我们是通过vue提交的 http://localhost:8080/groovy/execute?scriptimport com.example.groovytest.controller.LoginController; LoginController.num251222 还有个技巧: 而执行执行的,则是: 写的工具什么的,想直接使…...
Powershell WSL导出导入ubuntu22.04.5子系统
导出Linux子系统 导出位置在C盘下,根据自己的实际情况更改即可Write-Host "export ubuntu22.04.5" -ForegroundColor Green wsl --export Ubuntu-22.04 c:\Ubuntu-22.04.tar 导入Linux子系统 好处是目录可用在任意磁盘路径,便于迁移不同的设备之间Write-Host &quo…...
【005安卓开发方案调研】之Flutter+Dart技术开发安卓
基于2025年国内移动开发环境现状,结合多份行业分析报告和技术文档,对FlutterDart开发安卓应用的技术成熟度和生态适配性分析如下: 一、技术成熟度评估 1. 跨平台能力达到生产级标准 Flutter的Skia自渲染引擎和Dart的AOT/JIT双编译模式&…...
论文笔记(七十三)Gemini Robotics: Bringing AI into the Physical World
Gemini Robotics: Bringing AI into the Physical World 文章概括1. 引言2. Gemini 2.0的具身推理2.1. 具身推理问答(ERQA)基准测试2.2. Gemini 2.0的具身推理能力2.3. Gemini 2.0支持零样本和少样本机器人控制 3. 使用 Gemini Robotics 执行机器人动作3…...
AI + 医疗 Qwq大模型离线本地应用
通义千问Qwq-32b-FP16可用于社区医院、乡镇卫生院、诊所等小型医疗机构,替代专业合理用药系统,作为药品知识库,实现以下功能: 药品信息智能查询:检索药品的详细说明书、适应症、禁忌症、不良反应及药物相互作用等关键信…...
Vue 3 项目实现国际化指南 i18n
引言 在开发现代 Web 应用时,国际化(Internationalization,简称 i18n)已经成为一个不可或缺的功能。无论是面向全球用户的商业网站,还是需要支持多语言的企业应用,良好的国际化支持都能显著提升用户体验。本…...
元音辅音及其字母组合发音
文章目录 单元音长元音/ɑː//ɔ://u://i://ɜː/// 短元音/ʌ//ɒ//ʊ//ɪ//ə//e/ 双元音/eɪ//aɪ//ɔɪ//ɪə//eə//ʊə//əʊ//aʊ/ 辅音3个鼻辅音m n ŋ 5个独立浊辅音w j r l h 20个清浊相对的辅音s zʃ ʒf vθ p bt dk gts dztʃ dʒtr dr 以下是列举的部分字母组合…...
【Vitis AIE】FPGA图像处理 11 双线性插值 Bilinear Interpolation
双线性插值 https://github.com/Xilinx/Vitis-Tutorials/tree/2024.2/AI_Engine_Development/AIE/Design_Tutorials/11-Bilinear_Interpolation 简介 双线性插值是一种使用重复线性插值来插值两个变量函数的方法。它通常用于以下应用: 图像处理和计算机视觉&…...
Linux | 安装 Samba将ubuntu 的存储空间指定为windows 上的一个磁盘
01 安装 samba 文件来实现。比如把我们 ubuntu 的存储空间指定为我们 windows 上的一个磁盘,然后我们在这个磁盘里面创建 .c 文件,进行我们代码的修改和编写,可以安装 samba 文件来实现。 samba 是一种网络共享服务,可以通过网络访问我们指定的文件夹 02 第一步:下…...
一文说清预训练与微调:AI的双重训练法则
什么是预训练? 预训练是大型语言模型训练的第一步。它在资金和计算能力的支持下,通过深入分析大量的文本数据,使模型建立起语言的基本构架。在这一阶段,模型通过学习海量的书籍、文章和网页,识别出语言的语法、句法和…...
solana增加流动性和删除流动性
在 Solana 区块链上增加和删除流动性通常通过去中心化交易所(DEX)实现,例如 Raydium 或 Orca。以下是详细的操作流程和注意事项: 一、增加流动性 步骤: 1. 连接钱包 使用支持 Solana 的钱包(如 Phantom、…...
996引擎-接口测试:音效测试NPC
996引擎-接口测试:音效测试NPC 参考资料local offset = 1 -- 默认偏移量function main(player, newOffset)offset = newOffset or offset -- 更新偏移量local buttonWidth =...
javabean类,测试类,工具类都是什么?
JavaBean类 用来描述一类事物的类。比如Student、Teacher、Dog、Cat 例如下面的这个就是JavaBean类 package com.hong.static01demo;public class Student {//姓名,年龄,性别private String name;private int age;private String gender;public stati…...
基于C8051F020单片机的液晶显示,LCD1602并口驱动,单片机并口驱动LCD1602
一、前言 LCD1602是一种广泛使用的字符型液晶显示模块,有8根数据线和3根控制线E,RS和R/W,8根数据线与单片机P6连接,3根控制线与使用P1口的P1.4、P1.5、P1.6连接,VO连接了P1.7,通过给P1.7赋值0或1ÿ…...
miniconda安装保姆级教程|win11|深度学习环境配置
一、官网安装miniconda miniconda官网:Miniconda - Anaconda 点击Download按钮 在红框位置输入邮箱并点击submit,下载链接将会发到邮箱中 邮箱中将会收到如图所示邮件,点击下载 选择windows对应的miniconda安装包 miniconda安装包安装完成如…...
算力100问☞第92问:为什么各地热衷建设算力中心?
目录 1、宏观分析 2、政府角度分析 3、投资者角度分析 在数字化浪潮中,各地对算力中心建设的热情高涨,这一现象背后潜藏着诸多深层次的原因,涵盖了经济、科技、社会等多个维度,且彼此交织,共同驱动着这一发展趋势。 1、宏观分析 从经济结构转型的底层逻辑来看,全球经…...
HTML字符实体笔记
一、概述 在HTML中,某些字符具有特殊含义,不能直接用于网页内容显示,需要使用字符实体来代替。字符实体分为两类:字符实体名称和字符实体编号。字符实体名称由&开头,后跟实体名称,以分号;结束…...
Linux shell脚本-概述、语法定义、自定义变量、环境变量、预设变量、变量的特殊用法(转义字符、单双引号、大小括号)的验证
目录 1.shell概述 1.1作为应用程序: 1.2 shell 作为一门语言 2.shell 语法 2.1 shell脚本的定义与执行 (1)新建文件 (2)程序开头第一行 必须写shell的类型 (3)程序编写完后,…...
数据驱动进化:AI Agent如何重构手机交互范式?
如果说AIGC拉开了内容生成的序幕,那么AI Agent则标志着AI从“工具”向“助手”的跨越式进化。它不再是简单的问答机器,而是一个能够感知环境、规划任务并自主执行的智能体,更像是虚拟世界中的“全能员工”。 正如行业所热议的:“大…...
DL学习笔记:穿戴设备上的轻量级人体活动识别方法
Hello,大家好!这里是《Dream 的深度学习笔记》,本系列将聚焦三个学习方面: 论文解读:拆解经典论文与最新突破 技术实现:从模型搭建到实际部署 应用案例:涵盖图像识别、深度学习、人工智能等热门方向 让…...
拓展知识三:编码学及密码学
编码和密码的区别 研究密码变化的客观规律,应用于编制密码以保守通信秘密的,称为编码学;应用于破译密码以获取通信情报的,称为破译学,总称密码学。 编码和密码是两个不同的概念,它们的区别如下:…...
windows安装配置FFmpeg教程
1.先访问官网:https://www.gyan.dev/ffmpeg/builds/ 2.选择安装包Windows builds from gyan.dev 3. 下滑找到release bulids部分,选择ffmpeg-7.0.2-essentials_build.zip 4. 然后解压将bin目录添加path系统变量:\ffmpeg-7.0.2-essentials_bui…...
Qt/C++项目积累:4.远程升级工具 - 4.1 项目设想
背景: 桌面程序一般都支持远程升级,也是比较常用的场景设计。如酷狗音乐的升级,会提供两个选项,自动帮助安装或是新版本提醒,由用户来决定是否升级,都属于远程升级的应用及策略。 看看经过这块的功能了解及…...
同旺科技USB to SPI 适配器 ---- 指令循环发送功能
所需设备: 内附链接 1、同旺科技USB to SPI 适配器 1、周期性的指令一次输入,即可以使用 “单次发送” 功能,也可以使用 “循环发送” 功能,大大减轻发送指令的编辑效率; 2、 “单次发送” 功能,“发送数据…...
用 Pinia 点燃 Vue 3 应用:状态管理革新之旅
一、状态管理的范式转移:从 Flux 到 Composition ### 1.1 Vuex 的辉煌与局限 - **核心架构**:基于Flux模式的state/mutations/actions三件套 - **痛点显现**: - 类型推导困难:TypeScript支持需复杂配置 - 模块嵌套陷阱&#…...
