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

[数据结构]-AVL树

前言

作者:小蜗牛向前冲

名言:我可以接受失败,但我不能接受放弃

  如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正

目录

一、AVL树基本知识

1、概念

2、节点定义

3、插入

二、AVL树的旋转

1、右单旋

2、左单旋

 3、左右双旋

4、 右左双旋

三、AVL树的测试 

1、测试的补充代码

2、测试 


 本期学习目标:清楚什么是AVL树,模拟实现AVL树,理解四种旋转模型。 

一、AVL树基本知识

1、概念

       二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查 找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年 发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右 子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均 搜索长度

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

  • 它的左右子树都是AVL树
  • 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

 

2、节点定义

template<class k,class v>
struct AVLTreeNode
{pair<k, v>_kv;AVLTreeNode<k, v>* _left;AVLTreeNode<k, v>* _right;AVLTreeNode<k, v>* _parent;int _bf;//balance factor//带参数的构造函数AVLTreeNode(const pair<k,v>& kv):_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0){}
};

这里我们定义了三叉链来定义节点,最为特殊的是我们相对于二叉树,我们多了一个平衡 因子,这是维持AVL特性的关键,下面我们将围绕此展开对AVL树的构建。

注意:平衡因子 = 右树的高度-左树的高度

3、插入

AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么 AVL树的插入过程可以分为两步:

1. 按照二叉搜索树的方式插入新节点

2. 调整节点的平衡因子

对于插入最为重要的是平衡因子的更新,下面我们将讨论更新平衡因子情况:

是否要在更新平衡因子,要根据子树的高度:
1、如果parent->_bf==0,者说明以前的parent->_bf==-1或者parent->_bf==1
即是以前是一边高一边低,现在是插入到矮的一边,树的高度不变,不更新

2、如果parent->_bf==-1或者parent->_bf==-1,者以前parent->_bf==0
即是以前树是均衡的,现在插入让一边高了
子树的高度变了,要向上更新

3 、如果parent->_bf==-2或者parent->_bf==2,者以前parent->_bf==-1或者parent->_bf==1
现在树严重不平衡,让树旋转维持结构

//插入
bool Insert(const pair<k, v>& kv)
{if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;//找插入位置while (cur){//插入元素大于比较元素if (cur->_kv.first < kv.first){parent = cur;//继续往右树走cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;//继续往左树走cur = cur->_left;}else//插入元素于树中元素相等,不插入{return false;}}cur = new Node(kv);//链接节点if (parent->_kv.first > kv.first){parent->_left = cur;//更新parentcur->_parent = parent;}else{parent->_right = cur;//更新parentcur->_parent = parent;}//更新平衡因子while (parent)//parent为空,就更新到了根{//新增在树节点左边,parent->bf--//新增在树节点右边,parent->bf++if (cur == parent->_left){parent->_bf--;}else{parent->_bf++;}//是否要在更新平衡因子,要根据子树的高度://1、如果parent->_bf==0,者说明以前的parent->_bf==-1或者parent->_bf==1//即是以前是一边高一边低,现在是插入到矮的一边,树的高度不变,不更新//2、如果parent->_bf==-1或者parent->_bf==-1,者以前parent->_bf==0//即是以前树是均衡的,现在插入让一边高了//子树的高度变了,要向上更新//3 、如果parent->_bf==-2或者parent->_bf==2,者以前parent->_bf==-1或者parent->_bf==1//现在树严重不平衡,让树旋转维持结构//旋转://1、让子树的高度差不差过1//2、旋转过程中也要保存搜索树结构//3、边更新平衡因子//4、让这课树的高度保存和之前一样(旋转结束,不影响上层结构)if (parent->_bf == 0){break;}else if (parent->_bf == -1 || parent->_bf == 1){cur = parent;parent = parent->_parent;}//旋转else if (parent->_bf == -2 || parent->_bf == 2){//左单旋转if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}//右单旋else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}//左右双旋else if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}//右左双旋else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}else{assert(false);}//旋转完成,平衡因子已经更新跳出循环break;}else{assert(false);}}
}

二、AVL树的旋转

如果parent->_bf==-2或者parent->_bf==2,者以前parent->_bf==-1或者parent->_bf==1
现在树严重不平衡,让树旋转维持结构:

旋转的要求:

  • 让子树的高度差不差过1
  • 旋转过程中也要保存搜索树结构
  • 边更新平衡因子
  • 让这课树的高度保存和之前一样(旋转结束,不影响上层结构)

旋转的分类: 

  • 新节点插入较高左子树的左侧—左左:右单旋
  • 新节点插入较高右子树的右侧—右右:左单旋
  • 新节点插入较高左子树的右侧—左右:先左单旋再右单旋
  • 新节点插入较高右子树的左侧—右左:先右单旋再左单旋

1、右单旋

对于可能出现右旋转的情况的子树是多样的

 这里我们可以根据需要进行右单旋转抽像图进行理解

 

代码实现: 

//右单旋
void RotateR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;//b做60的右parent->_left = subLR;if (subLR){subLR->_parent = parent;}Node* ppNode = parent->_parent;//60做30的右subL->_right = parent;parent->_parent = subL;//60就是以前的根节点if (ppNode == nullptr){_root = subL;subL->_parent = ppNode;}else{//上层父节点的左边是子树的parentif (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}//更新平衡因子parent->_bf = subL->_bf = 0;
}

2、左单旋

 

代码实现:

 

void RotateL(Node * parent)
{Node* subR = parent->_right;//父节点的右子树Node* subRL = subR->_left;//右树的左树//让60左边链接到30的右边parent->_right = subRL;if (subRL){subRL->_parent = parent;}Node* ppNode = parent->_parent;//让30变成60的左边subR->_left = parent;parent->_parent = subR;//subR就是根节点if (ppNode == nullptr){_root = subR;_root->_parent = nullptr;}else{//上层父节点的左边是子树的parentif (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}//子树父节点和上层父节点链接subR->_parent = ppNode;}//更新平衡因子parent->_bf = subR->_bf = 0;
}

 3、左右双旋

对于双旋转来说:节点新增的位置不同,平衡因子最终也会不同,这里我们要进行分类讨论:

对于双旋转来说,最为重要的平衡因子的更新。 

 代码实现:

//左右双旋
void RotateLR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;//记录subLR的平衡因子int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);//根据不同情况更新平衡因子if (bf == 1)//在c点处新增(在subLR的右子树新增){subLR->_bf = 0;parent->_bf = 0;subL->_bf = -1;}else if(bf == -1) // 在b点处新增(在subLR的左子树新增){subLR->_bf = 0;subL->_bf = 0;parent->_bf = 1;}else if (bf == 0) //自己就是增点{subLR->_bf = 0;parent->_bf = 0;subL->_bf = 0;}else{assert(false);}
}

4、 右左双旋

这里同样也要进行分类讨论:

 

代码实现: 

//右左双旋
void RotateRL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;//记录subLR的平衡因子int bf = subRL->_bf;RotateR (parent->_right);RotateL(parent);//根据不同情况更新平衡因子if (bf == 1)//在c点处新增(在subLR的右子树新增){subR->_bf = 0;subRL->_bf = 0;parent->_bf = -1;}else if (bf == -1) // 在b点处新增(在subLR的左子树新增){subR->_bf = 1;subRL->_bf = 0;parent->_bf = 0;}else if (bf == 0) //自己就是增点{subR->_bf = 0;subRL->_bf = 0;parent->_bf = 0;}else{assert(false);}
}

三、AVL树的测试 

为了测试我们模拟实现的AVL树是否成功,还需要进行检查

1、测试的补充代码

树的高度:

int Height()
{return _Height(_root);
}
//求树的高度
int _Height(Node* root)
{//树高度为0if (root == nullptr){return 0;}//递归求左树的高度int Lh = _Height(root->_left);//递归求右树的高度int Rh = _Height(root->_right);return  Lh > Rh ? Lh + 1 : Rh + 1;
}

检查平衡因子

	//检测平衡因子bool _IsBalance(Node* root){if (root == nullptr){return true;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);if (rightHeight - leftHeight != root->_bf){cout << root->_bf << endl;cout << rightHeight - leftHeight << endl;cout << root->_kv.first << "平衡因子异常" << endl;return false;}return abs(rightHeight - leftHeight) < 2&& _IsBalance(root->_left)&& _IsBalance(root->_right);}

中序遍历

	void InOrder()//这是为了解决在外面调用,不好传根的问题{_InOrder(_root);}//中序遍历void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}

2、测试 

完整代码:

#pragma once
#include<time.h>
#include<assert.h>template<class k,class v>
struct AVLTreeNode
{pair<k, v>_kv;AVLTreeNode<k, v>* _left;AVLTreeNode<k, v>* _right;AVLTreeNode<k, v>* _parent;int _bf;//balance factor//带参数的构造函数AVLTreeNode(const pair<k,v>& kv):_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0){}
};
template<class k, class v>
struct AVLTree
{typedef AVLTreeNode<k,v> Node;
public://插入bool Insert(const pair<k, v>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;//找插入位置while (cur){//插入元素大于比较元素if (cur->_kv.first < kv.first){parent = cur;//继续往右树走cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;//继续往左树走cur = cur->_left;}else//插入元素于树中元素相等,不插入{return false;}}cur = new Node(kv);//链接节点if (parent->_kv.first > kv.first){parent->_left = cur;//更新parentcur->_parent = parent;}else{parent->_right = cur;//更新parentcur->_parent = parent;}//更新平衡因子while (parent)//parent为空,就更新到了根{//新增在树节点左边,parent->bf--//新增在树节点右边,parent->bf++if (cur == parent->_left){parent->_bf--;}else{parent->_bf++;}//是否要在更新平衡因子,要根据子树的高度://1、如果parent->_bf==0,者说明以前的parent->_bf==-1或者parent->_bf==1//即是以前是一边高一边低,现在是插入到矮的一边,树的高度不变,不更新//2、如果parent->_bf==-1或者parent->_bf==-1,者以前parent->_bf==0//即是以前树是均衡的,现在插入让一边高了//子树的高度变了,要向上更新//3 、如果parent->_bf==-2或者parent->_bf==2,者以前parent->_bf==-1或者parent->_bf==1//现在树严重不平衡,让树旋转维持结构//旋转:if (parent->_bf == 0){break;}else if (parent->_bf == -1 || parent->_bf == 1){cur = parent;parent = parent->_parent;}//旋转else if (parent->_bf == -2 || parent->_bf == 2){//左单旋转if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}//右单旋else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}//左右双旋else if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}//右左双旋else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}else{assert(false);}//旋转完成,平衡因子已经更新跳出循环break;}else{assert(false);}}}void RotateL(Node * parent){Node* subR = parent->_right;//父节点的右子树Node* subRL = subR->_left;//右树的左树//让60左边链接到30的右边parent->_right = subRL;if (subRL){subRL->_parent = parent;}Node* ppNode = parent->_parent;//让30变成60的左边subR->_left = parent;parent->_parent = subR;//subR就是根节点if (ppNode == nullptr){_root = subR;_root->_parent = nullptr;}else{//上层父节点的左边是子树的parentif (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}//子树父节点和上层父节点链接subR->_parent = ppNode;}//更新平衡因子parent->_bf = subR->_bf = 0;}//右单旋void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;//b做60的右parent->_left = subLR;if (subLR){subLR->_parent = parent;}Node* ppNode = parent->_parent;//60做30的右subL->_right = parent;parent->_parent = subL;//60就是以前的根节点if (ppNode == nullptr){_root = subL;subL->_parent = ppNode;}else{//上层父节点的左边是子树的parentif (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}//更新平衡因子parent->_bf = subL->_bf = 0;}//左右双旋void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;//记录subLR的平衡因子int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);//根据不同情况更新平衡因子if (bf == 1)//在c点处新增(在subLR的右子树新增){subLR->_bf = 0;parent->_bf = 0;subL->_bf = -1;}else if(bf == -1) // 在b点处新增(在subLR的左子树新增){subLR->_bf = 0;subL->_bf = 0;parent->_bf = 1;}else if (bf == 0) //自己就是增点{subLR->_bf = 0;parent->_bf = 0;subL->_bf = 0;}else{assert(false);}}//右左双旋void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;//记录subLR的平衡因子int bf = subRL->_bf;RotateR (parent->_right);RotateL(parent);//根据不同情况更新平衡因子if (bf == 1)//在c点处新增(在subLR的右子树新增){subR->_bf = 0;subRL->_bf = 0;parent->_bf = -1;}else if (bf == -1) // 在b点处新增(在subLR的左子树新增){subR->_bf = 1;subRL->_bf = 0;parent->_bf = 0;}else if (bf == 0) //自己就是增点{subR->_bf = 0;subRL->_bf = 0;parent->_bf = 0;}else{assert(false);}}int Height(){return _Height(_root);}//求树的高度int _Height(Node* root){//树高度为0if (root == nullptr){return 0;}//递归求左树的高度int Lh = _Height(root->_left);//递归求右树的高度int Rh = _Height(root->_right);return  Lh > Rh ? Lh + 1 : Rh + 1;}bool IsAVLTree(){return _IsBalance(_root);}//检测平衡因子bool _IsBalance(Node* root){if (root == nullptr){return true;}int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);if (rightHeight - leftHeight != root->_bf){cout << root->_bf << endl;cout << rightHeight - leftHeight << endl;cout << root->_kv.first << "平衡因子异常" << endl;return false;}return abs(rightHeight - leftHeight) < 2&& _IsBalance(root->_left)&& _IsBalance(root->_right);}void InOrder()//这是为了解决在外面调用,不好传根的问题{_InOrder(_root);}//中序遍历void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}private:Node* _root = nullptr;
};void TestAVLTree1()
{//int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };/*int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };*/int a[] = { 30,60,90 };AVLTree<int, int> t;for (auto e : a){t.Insert(make_pair(e, e));}t.InOrder();cout << t.IsAVLTree() << endl;
}
void TestAVLTree2()
{srand(time(0));const size_t N = 100000;AVLTree<int, int> t;for (size_t i = 0; i < N; ++i){size_t x = rand();t.Insert(make_pair(x, x));/*cout << t.IsAVLTree() << endl;*/}cout << t.IsAVLTree() << endl;
}

这里我们分别进行简单 TestAVLTree1()和用生成随机数字生成的数字进行测试TestAVLTree2()

如果成功就会打印1.

相关文章:

[数据结构]-AVL树

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、AVL树基…...

内存池的面试整理

文章思路来源 如何实现无锁申请&#xff1f; 每个线程申请自己的TreadCacheTLS对象&#xff0c;来管理自己的freeList数组。小内存的大小&#xff1f; 0-256K&#xff0c;并且对申请到的内存进行字节对齐&#xff0c;保证申请到的内存可以映射到对应的freeList中。映射规则&am…...

优化记录 -- 记一次搜索引擎(SOLR)优化

业务场景 某服务根据用户相关信息&#xff0c;使用搜索引擎进行数据检索 软件配置 solr 1台&#xff1a;32c 64g 数据10gb左右&#xff0c;版本 7.5.5 应用服务器1台&#xff1a;16c 64g 应用程序 3节点 问题产生现象 1、因业务系统因处理能不足&#xff0c;对业务系统硬件…...

电力感知边缘计算网关产品设计方案-网关系统通信架构方案

1.边缘协同控制模发 能针对建筑、充电桩、分布式储能、分布式光伏等典型设备建立对应物模型、完成数据采集通信协议设计和控制指令交互设计,能针对建筑、充换电站等典型场景提出具体实施方案和人工智能控制算法和逻辑。物模型、通信协议设计和控制指令交互设计科学、先进,能…...

RabbitMQ消息的可靠性

RabbitMQ消息的可靠性 一 生产者的可靠性 生产者重试 有时候由于网络问题&#xff0c;会出现连接MQ失败的情况&#xff0c;可以配置重连机制 注意&#xff1a;SpringAMQP的重试机制是阻塞式的&#xff0c;重试等待的时候&#xff0c;当前线程会等待。 spring:rabbitmq:conne…...

Opengl 纹理(知识点)

纹理&#xff08;知识点&#xff09; 以下是纹理用到的知识点&#xff0c;至于具体流程操作请参考&#xff1a; https://learnopengl.com/Getting-started/Textures 纹理环绕 纹理环绕&#xff08;Texture Wrapping&#xff09;的作用是定义在纹理坐标超出标准范围时系统如何…...

Centos 7 安装yum(针对python卸载yum出错)

提前下载所需安装包&#xff0c;按照下面顺序安装即可完成&#xff0c;每个依赖包必须正确安装 下载地址&#xff1a;http://mirrors.163.com/centos/7/os/x86_64/Packages/ rpm -qa|grep python|xargs rpm -ev --allmatches --nodeps ##强制删除已安装程序及其关联 whereis …...

substr()与substring()的区别

在 JavaScript 编程语言中&#xff0c;substr() 和 substring() 都是字符串函数&#xff0c;用于截取指定位置的子字符串。虽然这两个函数都可以用于截取字符串&#xff0c;但它们之间存在一些区别。 substr() 语法&#xff1a;string.substr(start,length) 参数值&#xff1a…...

MacOS 成为恶意软件活动的目标

Malwarebytes 警告称&#xff0c;一个针对 Mac 操作系统 (OS) 的数据窃取程序正在通过虚假的网络浏览器更新分发给毫无戒心的目标。 Atomic Stealer&#xff0c;也称为 AMOS&#xff0c;是 Mac OS 上流行的窃取程序。 Atomic Stealer (AMOS) 恶意软件最近被发现使用“ClearFa…...

从0开始学习JavaScript--JavaScript生成器

JavaScript生成器&#xff08;Generator&#xff09;是一项强大的语言特性&#xff0c;它允许函数在执行过程中被暂停和恢复&#xff0c;从而实现更灵活的控制流。本文将深入探讨JavaScript生成器的基本概念、用法&#xff0c;并通过丰富的示例代码展示其在实际应用中的优势和强…...

householder进行矩阵QR分解

文章目录 1. Householder 进行QR分解 1. Householder 进行QR分解 A Q R (1) AQR\tag1 AQR(1) A [ 1 2 0 1 1 0 3 1 1 0 3 2 1 2 0 2 ] (2) A\begin{bmatrix}1&2&0&1\\\\1&0&3&1\\\\1&0&3&2\\\\1&2&0&2\end{bmatrix}\tag2 A…...

利用叉积计算向量的旋向及折线段的拐向

一、向量叉积 两个向量 u u u、 v v v的叉积写作 u v n ∥ u ∥ ∥ v ∥ s i n θ \mathbf{u \times v n \left \| u \right \| \left \| v \right \| sin\theta } uvn∥u∥∥v∥sinθ 式中&#xff0c; n n n: 与 u u u、 v v v均垂直的单位向量&#xff0c;theta是两向量…...

Vmware 扩展硬盘空间后的操作-Ubuntu

在VMware中扩展了Ubuntu虚拟机的硬盘容量后&#xff0c;你需要在Ubuntu内部进行操作才能使用新增的空间。过程包括为增加的空间建立分区、格式化以及挂载该分区供使用。下面是具体的步骤&#xff1a; 首先登录到你的Ubuntu系统&#xff0c;用lsblk命令查看分区情况。这样你可以…...

Rust错误处理:Result

文章目录 简介错误匹配 Rust基础教程&#xff1a; 初步⚙ 所有权⚙ 结构体和枚举类⚙ 函数进阶⚙ 泛型和特征⚙ 并发和线程通信⚙ cargo包管理⚙ 可空类型Option Rust进阶教程&#xff1a; 用宏实现参数可变的函数⚙ 类函数宏 简介 Rust中没有提供类似try…catch之类…...

1410.HTML 实体解析器

​​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;1410. HTML 实体解析器 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 使用map存放特殊字符串及其应被替换为的字符串。然后遍历字符串替换 map 中的字符串即可。 解题代码&#xff1a; …...

Python通过串口收发文件

单位内外网是隔离的,USB对拷线被禁用,安全优盘使用太费事,就想到了通过串口传输文件. import serial from xmodem import XMODEM import osdef Send_File(filepath, portCOM8, baudrate115200):bn os.path.basename(filepath)filesize os.stat(filepath).st_sizestrSendFile…...

[crash] cxa_pure_virtual 崩溃分析与原理

摘要&#xff1a;工作过程中处理线上的崩溃时发现了一例cxa_pure_virtual相关的crash&#xff0c;直接看堆栈基本山很容易确认是有异步调用导致出发了ABI的异常。但是对于为什么会触发cxa_pure_virtual虽然有大致的猜测但是没有直接的证据&#xff0c;因此本文主要描述触发该类…...

2023年学习Go语言是否值得?探索Go语言的魅力

关注公众号【爱发白日梦的后端】分享技术干货、读书笔记、开源项目、实战经验、高效开发工具等&#xff0c;您的关注将是我的更新动力&#xff01; 作为一门流行且不断增长的编程语言&#xff0c;Go语言在2023年是否值得学习呢&#xff1f;让我们来看看学习Go语言的好处以及为何…...

【C++11】=default与=delete关键字使用详解

系列文章目录 C11新特性使用详解-持续更新 文章目录 系列文章目录一、default关键字1. 为什么要引入default关键字2. 注意事项3. 使用default关键字有什么好处4.实例代码 二、delete关键字1. 为什么要引入delete关键字2. 注意事项3. 使用场景3.1删除默认构造函数3.2 删除拷贝构…...

[开源]Web端的P2P文件传输工具,简单安全高效的P2P文件传输服务

一、开源项目简介 小鹿快传 - 在线P2P文件传输工具 小鹿快传是一款Web端的P2P文件传输工具&#xff0c;使用了WebRTC技术实现P2P连接和文件传输。 二、开源协议 使用MIT开源协议 三、界面展示 产品截图 四、功能概述 简单安全高效的P2P文件传输服务 小鹿快传是一款Web端…...

5分钟上手KeymouseGo:让电脑自动完成重复工作的免费神器

5分钟上手KeymouseGo&#xff1a;让电脑自动完成重复工作的免费神器 【免费下载链接】KeymouseGo 类似按键精灵的鼠标键盘录制和自动化操作 模拟点击和键入 | automate mouse clicks and keyboard input 项目地址: https://gitcode.com/gh_mirrors/ke/KeymouseGo 你是否…...

ESP32离线语音助手伴侣端部署:基于Speckit-Companion的本地智能家居控制

1. 项目概述与核心价值最近在折腾一个很有意思的项目&#xff0c;叫alfredoperez/speckit-companion。乍一看这个仓库名&#xff0c;可能有点摸不着头脑&#xff0c;但如果你是一个经常和硬件、嵌入式系统或者物联网设备打交道的开发者&#xff0c;尤其是接触过像 ESP32、ESP82…...

养虾成功!OpenClaw 接入微信全记录(附配置模型关键步骤)

微信发布了Clawbot插件&#xff0c;意味着可以将OpenClaw接入生态啦。不需要企业资质&#xff0c;也不用搞复杂的开发&#xff0c;只需四步就能拥有一个24小时在线的AI私人管家。本文将一步步带你完成OpenClaw接入微信的全流程&#xff0c;帮你轻松开启AI助手的智能对话体验。 …...

期货量化模拟转实盘检查清单:延迟、成交偏差与异常处理

前言 模拟阶段表现稳定&#xff0c;转实盘后突然失真&#xff0c;是期货量化最常见的落地断层。 问题通常不在策略公式&#xff0c;而在执行链路细节&#xff1a;延迟、成交偏差、异常处理。转实盘前如果没有检查清单&#xff0c;团队容易把环境问题误判成策略失效。 一、延迟检…...

倍福TwinCAT 3 运动控制从入门到精通 | 01:TwinCAT3 NC PTP运动控制底层架构全解析|从三层轴模型、周期机制到轴类型深度详解(新手入门到工控进阶必看)

摘要:倍福TwinCAT3作为PC架构自动化控制的标杆平台,NC PTP点对点运动控制是工业伺服定位、多轴电子齿轮、电子凸轮同步的底层核心。不少工控新手入门TC3运动开发时,普遍存在认知盲区:分不清PLC轴、NC轴、物理轴三者层级关系,看不懂NC双任务周期的差异逻辑,对EtherCAT、脉…...

为什么说OpenProject是中小团队最值得尝试的开源项目管理工具?

为什么说OpenProject是中小团队最值得尝试的开源项目管理工具&#xff1f; 【免费下载链接】openproject OpenProject is the leading open source project management software. 项目地址: https://gitcode.com/GitHub_Trending/op/openproject 还在为高昂的SaaS项目管…...

创业团队如何借助 Taotoken 统一管理多个 AI 模型的 API 成本与用量

创业团队如何借助 Taotoken 统一管理多个 AI 模型的 API 成本与用量 1. 多模型统一接入的工程挑战 创业团队在开发智能应用时&#xff0c;往往需要同时调用多种大模型能力。例如对话场景可能混合使用 Claude 的连贯性与 OpenAI 的响应速度&#xff0c;而不同模块对模型特性有…...

通过 curl 命令直接调用 Taotoken 大模型 API 的简易方法

通过 curl 命令直接调用 Taotoken 大模型 API 的简易方法 1. 准备工作 在开始调用 Taotoken 大模型 API 之前&#xff0c;需要确保已经准备好 API Key 和模型 ID。登录 Taotoken 控制台&#xff0c;在「API 密钥」页面可以创建和管理 API Key。模型 ID 可以在「模型广场」查看…...

SchoolCMS:如何用开源技术构建现代化教务管理系统?

SchoolCMS&#xff1a;如何用开源技术构建现代化教务管理系统&#xff1f; 【免费下载链接】schoolcms 中国首个开源学校教务管理系统、网站布局自动化、学生/成绩/教师、成绩查询 项目地址: https://gitcode.com/gh_mirrors/sc/schoolcms SchoolCMS作为中国首个开源学校…...

3分钟掌握APK Installer:Windows上安装Android应用的终极免费方案

3分钟掌握APK Installer&#xff1a;Windows上安装Android应用的终极免费方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 还在为在Windows电脑上安装Android应用而…...