【知识讲解】 AVL树从基本成员的介绍到核心接口的实现(插入、判断、删除等等)

发布时间:2026/7/7 23:27:12

【知识讲解】 AVL树从基本成员的介绍到核心接口的实现(插入、判断、删除等等)
目录前言Part1. AVL树相关成员介绍Part1.1. AVL树节点相关Part1.2. AVL树本体Part2. 四大旋转操作Part2.1. 左单旋Part2.2. 右单旋Part2.3. 左右双旋Part2.4. 右左双旋Part3. 平衡因子作用解析Part3.1. 平衡因子与旋转Part3.2. 平衡因子与向上调整插入Part4. 插入操作Part5. 判断操作Part6. Find接口Part7. 删除操作Part7.1. 平衡因子与向上调整删除Part7.2. 删除的旋转操作Part7.3. 删除的实现Part8. 反思与总结Part9. 代码分享Part9.1. AVL实现Part9.2. 测试Part10. 结语前言前置知识【知识讲解】 二叉搜索树的相关知识与实现-CSDN博客AVL树作为经典的数据结构之一他的有些接口会稍显复杂接下来跟随小编的视角来剖析一下它的全部吧。lets go!!!!!!!!!Part1. AVL树相关成员介绍我们先来看构成AVL树的成员是哪些这方便我们去介绍后续的内容我们来看Part1.1. AVL树节点相关我们先来看代码templateclass k,class v struct AVLTreeNode { std::pairk, v _kv; AVLTreeNodek, v* _left; AVLTreeNodek, v* _right; AVLTreeNodek, v* _parent; int _bf; AVLTreeNode(const std::pairk, v kv) :_kv(kv) , _left(nullptr) , _right(nullptr) , _parent(nullptr) , _bf(0) { } };我们来对各个成员详细介绍一下1_kv存储数据的地方key、value。2_left、_right当前节点的左右节点。3_parent当前节点的父亲节点。4_bf平衡因子用于衡量当前节点左右子树的情况_bf当前节点的右子树高度减去其左子树高度插入操作时插到左子树_bf--反之后续调整旋转的核心Part1.2. AVL树本体这个就比较简洁了我们来看代码typedef AVLTreeNodek, v Node; Node* _root nullptr;通过一个_root来统一管理整棵树。Part2. 四大旋转操作虽然这个按道理来说应该放到后面来讲但是把这个单拿出来详细讲解会对后面的的插入删除有很大的帮助毕竟这个就是整个AVL树的核心。四大旋转操作分为左单旋、右单旋、左右双旋、右左双旋我们来分别看看吧Part2.1. 左单旋代码实现void RotateL(Node* parent) { Node* subR parent-_right; Node* subRL subR-_left; subR-_left parent; parent-_right subRL; if (subRL ! nullptr)//当h0的情况 { subRL-_parent parent; } subR-_parent parent-_parent;//记得还要更新_parent if (parent _root) { _root subR; } else { if (parent-_parent-_left parent) { parent-_parent-_left subR; } else { parent-_parent-_right subR; } } parent-_parent subR; parent-_bf 0;//更新平衡因子根据图片上来看 subR-_bf 0; }Part2.2. 右单旋代码实现void RotateR(Node* parent)//逻辑同上 { Node* subL parent-_left; Node* subLR subL-_right; parent-_left subLR; subL-_right parent; if (subLR ! nullptr) { subLR-_parent parent; } subL-_parent parent-_parent; if (parent _root) { _root subL; } else { if (parent-_parent-_left parent) { parent-_parent-_left subL; } else { parent-_parent-_right subL; } } parent-_parent subL; subL-_bf 0; parent-_bf 0; }Part2.3. 左右双旋void RotateLR(Node* parent) { Node* subL parent-_left; int bf subL-_right-_bf; RotateL(subL); RotateR(parent); if (bf 1)//更新平衡因子 //由于上面左旋右旋他对于平衡因子都会置为0 估值要修改不是0的就可以 { subL-_bf -1; } else if (bf -1) { parent-_bf 1; } else if (bf 0) { ; } else { assert(false); } }为什么这里要先采取一个左旋再来右旋呢首先这个场景下是由于左边太‘重’才导致的不平衡因此我们要把左边的节点掰到右边去这样才可以达到平衡但是这个场景又不像上面的右单旋直接右单旋是解决不了问题的。我们可以对比一下两者有什么区别两者的区别就在于右单旋在B这个子树中他的重量是全部都在左边左右单旋这个场景他是重在右边因此我们要先用左单旋把重量先移到左边让这个场景变成适用右单旋的场景再用右单旋解决问题。这里的平衡因子的更新也是充满细节我们来看也就是说新增节点具体在左子树右子树或者自身作为叶子结点的时候平衡因子的更新是有区别的我们可以直接依靠看c结点的_bf来判断是加到哪了从而来更新上面的平衡因子。Part2.4. 右左双旋void RotateRL(Node* parent)//逻辑同上 { Node* subR parent-_right; int bf subR-_left-_bf; RotateR(subR); RotateL(parent); if (bf 1) { parent-_bf -1; } else if (bf -1) { subR-_bf 1; } else if (bf 0) { ; } else { assert(false); } }Part3. 平衡因子作用解析上面我们这么大费周章的修改平衡因子是为了什么他的这个作用又是什么?实际上我们可以只通过两个结点的_bf就可以知道我们用哪种旋转了为什么我们来看Part3.1. 平衡因子与旋转旋转什么时候发生当这个节点不平衡的时候我们具体要对应与哪种旋转呢我们来看1当A处的_bf为2时候说明右边节点高度高则我们在最后一定要右旋但是在那之前具体要左旋来调整还是不要就要具体来看了具体到哪看自然是到右边去看因为是右子树比较重看什么看C处的_bf值如果为1说明新加的节点是在C的右边也就是纯粹的右边重也就是只需要一个整体的右旋就可以解决。反之要是为-1说明新加的是在左边就要先局部左旋将整体调整为右旋的模型在整体右旋解决。2 A处为-2逻辑同上。也就是说我们在遇到不平衡的节点时我们根据他是2还是-2具体在到出问题的那边子树在看那边的_bf值判断调用哪种旋转调整。Part3.2. 平衡因子与向上调整插入当我们A处的_bf不为2、-2时候怎么办什么时候我们要继续向上更新这里更新的依据是什么?旋转后怎么办还要继续向上调整吗针对这些问题我们来看首先我们是否向上调整关键在于我们一系列操作是否改变了树的高度我们来看上面的图我们修改的这个树也是上面的结点的子树当我们调整的这个树高度改变那么在上面看来就是它的一颗左子树与其右子树之间的高度差改变也就是我们要继续向上调整了。那平衡因子是怎么昭示高度改变呢我们来看1调整后_bf为0说明原本其为1/-1即就是原本它的子树有一个高现在相当于加到那个比较矮的子树上了相当于平衡了高度不变不用向上调整。2调整后_bf为1/-1说明原本为0不可能是2/-2不符合AVL树说明之前出问题了0就说明之前是平衡的现在1/-1一边子树高了高度改变要向上调整。为什么在插入操作流程旋转不用继续上向上调整了我们来看我们可以数一数调整前高度为h2调整后也是对于上面四个都是自然不用继续调整。前置知识差不多了我们来看插入和删除吧Part4. 插入操作我们来直接看代码bool insert(const std::pairk, v kv) { if (_root nullptr) { _root new Node(kv); return true; } Node* cur _root; Node* parent nullptr; while (cur) { if (cur-_kv.first kv.first) { parent cur; cur cur-_left; } else if(cur-_kv.first kv.first) { parent cur; cur cur-_right; } else { return false; } } cur new Node(kv); if (parent-_kv.first kv.first) { parent-_left cur; } else { parent-_right cur; } cur-_parent parent; //前面这些都是二叉平衡树的插入流程 不熟悉的可以看我前面博客 while (parent)//当parent为nullptr自动退出 { if (cur parent-_left)//根据新加入的节点更新 { parent-_bf--; } else { parent-_bf; } if (parent-_bf 0)//为0不用向上更新 退出 { break; } else if (parent-_bf 1 || parent-_bf -1)//1/-1继续向上更新 { cur parent; parent parent-_parent; } else if(parent-_bf 2 || parent-_bf -2)//根据_bf来决定用什么旋转 { if (parent-_bf -2 cur-_bf -1) { RotateR(parent); } else if (parent-_bf 2 cur-_bf 1) { RotateL(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); } } return true; }插入操作就是综合前面的知识来还结合了之前二叉搜索树的插入操作接下来我们来看看其他的接口吧。Part5. 判断操作我们来看代码void IsAVLTree()const { if (_IsAVLTree(_root) -1) { cout NO endl; } else { cout YES endl; } } int _IsAVLTree(Node* root)const//利用后序遍历 从叶子节点往上判断 时间复杂度为ON { if (root nullptr) { return 0; } int left _IsAVLTree(root-_left); int right _IsAVLTree(root-_right); if (left -1 || right -1) { return -1; } if (abs(left - right) 1 || root-_bf ! right - left)//检查左右高度差以及_bf是否满足条件 { return -1; } if (left right) { right left; } return right 1; }Part6. Find接口我们来看代码Node* Find(const k key)//与二叉搜索树一致 { Node* cur _root; while (cur ! nullptr) { if (cur-_kv.second key) { cur cur-_left; } else if (cur-_kv.second key) { cur cur-_right; } else { return cur; } } return nullptr; }Part7. 删除操作删除的逻辑大致上与上面插入相似不过在一些地方还是有所区别我们来看看吧Part7.1. 平衡因子与向上调整删除删除不与插入相似对于相同的平衡因子数值两者的操作会不一样来看看吧1当_bf为0时说明之前的_bf数值为1或者-1也就是说之前会有一棵子树的高度高于另一棵现在删去了多的那一个导致高度改变需要向上调整。2当_bf为1/-1时说明之前为0现在是在两个高度相同的子树中的一个删去了不影响树的整体高度故直接停止向上调整。3当_bf为2/-2时旋转调整这个与插入有很大区别来具体看看吧。Part7.2. 删除的旋转操作当A处的_bf为2C处为1时我们来看旋转的过程由于高度改变了所以在旋转后还要向上调整对于插入的四个情况是这样的但是这里与上面的模型不同b、c的_bf还可以为0我们来看看当其为0的时候是什么情况所以在这种情况下不用向上调整了但要注意调整A、B的_bf。Part7.3. 删除的实现我们来看代码void erase(const k key) { Node* cur Find(key);//找到节点 if (cur nullptr) return; Node* parent cur-_parent; int curn 0;//用这个来标记上次处理是在左子还是右子 if (cur-_left nullptrcur-_right!nullptr)//这些与二叉搜索树相似 { if (cur _root) { _root cur-_right; _root-_parent nullptr; delete cur; return; } if (parent-_left cur) { parent-_left cur-_right; cur-_right-_parent parent; curn -1; } else { parent-_right cur-_right; cur-_right-_parent parent; curn 1; } delete cur; } else if (cur-_left ! nullptr cur-_right nullptr) { if (cur _root) { _root cur-_left; _root-_parent nullptr; delete cur; return; } if (parent-_left cur) { parent-_left cur-_left; cur-_left-_parent parent; curn -1; } else { parent-_right cur-_left; cur-_left-_parent parent; curn 1; } delete cur; } else if (cur-_left nullptr cur-_right nullptr) { if (cur _root) { _root nullptr; delete cur; return; } if (parent-_left cur) { parent-_left nullptr; curn -1; } else { parent-_right nullptr; curn 1; } delete cur; } else { Node* replace cur-_right; while (replace-_left ! nullptr) { replace replace-_left; } parent replace-_parent; cur-_kv replace-_kv; if (parent-_left replace) { parent-_left replace-_right; if(replace-_right!nullptr) replace-_right-_parent parent; curn -1; } else { parent-_right replace-_right; if (replace-_right ! nullptr) replace-_right-_parent parent; curn 1; } delete replace; } cur parent-_left; if (curn 1) { cur parent-_right; } while (parent) { if (curn-1)//更新_bf { parent-_bf; } else { parent-_bf--; } if (parent-_bf 1 || parent-_bf -1)//为1/-1时候退出向上调整 { break; } else if (parent-_bf 0)//为0的时候更新_bf { cur parent; parent parent-_parent; if (parent nullptr) { break; } curn 1; if (cur parent-_left) { curn -1; } } else if (parent-_bf -2)//依靠_bf来旋转 { cur parent-_left; if (cur-_bf -1) { RotateR(parent); parent cur-_parent; } else if(cur-_bf 1) { RotateLR(parent); parent parent-_parent-_parent; cur cur-_parent; } else//为0的时候 { RotateR(parent); parent-_bf -1; cur-_bf 1; return; } if (parent nullptr) { break; } curn 1; if (cur parent-_left) { curn -1; } } else if (parent-_bf 2) { cur parent-_right; if (cur-_bf 1) { RotateL(parent); parent cur-_parent; } else if (cur-_bf -1) { RotateRL(parent); parent parent-_parent-_parent; cur cur-_parent; } else { RotateL(parent); parent-_bf 1; cur-_bf -1; return; } if (parent nullptr) { break; } curn 1; if (cur parent-_left) { curn -1; } } } }Part8. 反思与总结通过上面的一系列过程其实可以认识到一个结论那就是整个调整的过程就是依靠平衡因子来实现的建立模型是为了具象化平衡因子带来的影响以及在调整后高度是否改变从而来影响是否继续向上调整。所以平衡因子是全局的关键。Part9. 代码分享Part9.1. AVL实现#pragma once #includeiostream #includeassert.h #includealgorithm #includecstdlib #includevector using namespace std; templateclass k,class v struct AVLTreeNode { std::pairk, v _kv; AVLTreeNodek, v* _left; AVLTreeNodek, v* _right; AVLTreeNodek, v* _parent; int _bf; AVLTreeNode(const std::pairk, v kv) :_kv(kv) , _left(nullptr) , _right(nullptr) , _parent(nullptr) , _bf(0) { } }; templateclass k,class v class AVLTree { typedef AVLTreeNodek, v Node; public: AVLTree() default; bool insert(const std::pairk, v kv) { if (_root nullptr) { _root new Node(kv); return true; } Node* cur _root; Node* parent nullptr; while (cur) { if (cur-_kv.first kv.first) { parent cur; cur cur-_left; } else if(cur-_kv.first kv.first) { parent cur; cur cur-_right; } else { return false; } } cur new Node(kv); if (parent-_kv.first kv.first) { parent-_left cur; } else { parent-_right cur; } cur-_parent parent; while (parent) { if (cur parent-_left) { parent-_bf--; } else { parent-_bf; } 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) { RotateR(parent); } else if (parent-_bf 2 cur-_bf 1) { RotateL(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); } } return true; } void erase(const k key) { Node* cur Find(key); if (cur nullptr) return; Node* parent cur-_parent; int curn 0; if (cur-_left nullptrcur-_right!nullptr) { if (cur _root) { _root cur-_right; _root-_parent nullptr; delete cur; return; } if (parent-_left cur) { parent-_left cur-_right; cur-_right-_parent parent; curn -1; } else { parent-_right cur-_right; cur-_right-_parent parent; curn 1; } delete cur; } else if (cur-_left ! nullptr cur-_right nullptr) { if (cur _root) { _root cur-_left; _root-_parent nullptr; delete cur; return; } if (parent-_left cur) { parent-_left cur-_left; cur-_left-_parent parent; curn -1; } else { parent-_right cur-_left; cur-_left-_parent parent; curn 1; } delete cur; } else if (cur-_left nullptr cur-_right nullptr) { if (cur _root) { _root nullptr; delete cur; return; } if (parent-_left cur) { parent-_left nullptr; curn -1; } else { parent-_right nullptr; curn 1; } delete cur; } else { Node* replace cur-_right; while (replace-_left ! nullptr) { replace replace-_left; } parent replace-_parent; cur-_kv replace-_kv; if (parent-_left replace) { parent-_left replace-_right; if(replace-_right!nullptr) replace-_right-_parent parent; curn -1; } else { parent-_right replace-_right; if (replace-_right ! nullptr) replace-_right-_parent parent; curn 1; } delete replace; } cur parent-_left; if (curn 1) { cur parent-_right; } while (parent) { if (curn-1) { parent-_bf; } else { parent-_bf--; } if (parent-_bf 1 || parent-_bf -1) { break; } else if (parent-_bf 0) { cur parent; parent parent-_parent; if (parent nullptr) { break; } curn 1; if (cur parent-_left) { curn -1; } } else if (parent-_bf -2) { cur parent-_left; if (cur-_bf -1) { RotateR(parent); parent cur-_parent; } else if(cur-_bf 1) { RotateLR(parent); parent parent-_parent-_parent; cur cur-_parent; } else { RotateR(parent); parent-_bf -1; cur-_bf 1; return; } if (parent nullptr) { break; } curn 1; if (cur parent-_left) { curn -1; } } else if (parent-_bf 2) { cur parent-_right; if (cur-_bf 1) { RotateL(parent); parent cur-_parent; } else if (cur-_bf -1) { RotateRL(parent); parent parent-_parent-_parent; cur cur-_parent; } else { RotateL(parent); parent-_bf 1; cur-_bf -1; return; } if (parent nullptr) { break; } curn 1; if (cur parent-_left) { curn -1; } } } } void InOrder()const { _InOredr(_root); cout endl; } void IsAVLTree()const { if (_IsAVLTree(_root) -1) { cout NO endl; } else { cout YES endl; } } size_t Height()const { return _Height(_root); } size_t Size()const { return _Size(_root); } Node* Find(const k key) { Node* cur _root; while (cur ! nullptr) { if (cur-_kv.second key) { cur cur-_left; } else if (cur-_kv.second key) { cur cur-_right; } else { return cur; } } return nullptr; } private: void RotateR(Node* parent) { Node* subL parent-_left; Node* subLR subL-_right; parent-_left subLR; subL-_right parent; if (subLR ! nullptr) { subLR-_parent parent; } subL-_parent parent-_parent; if (parent _root) { _root subL; } else { if (parent-_parent-_left parent) { parent-_parent-_left subL; } else { parent-_parent-_right subL; } } parent-_parent subL; subL-_bf 0; parent-_bf 0; } void RotateL(Node* parent) { Node* subR parent-_right; Node* subRL subR-_left; subR-_left parent; parent-_right subRL; if (subRL ! nullptr) { subRL-_parent parent; } subR-_parent parent-_parent; if (parent _root) { _root subR; } else { if (parent-_parent-_left parent) { parent-_parent-_left subR; } else { parent-_parent-_right subR; } } parent-_parent subR; parent-_bf 0; subR-_bf 0; } void RotateLR(Node* parent) { Node* subL parent-_left; int bf subL-_right-_bf; RotateL(subL); RotateR(parent); if (bf 1) { subL-_bf -1; } else if (bf -1) { parent-_bf 1; } else if (bf 0) { ; } else { assert(false); } } void RotateRL(Node* parent) { Node* subR parent-_right; int bf subR-_left-_bf; RotateR(subR); RotateL(parent); if (bf 1) { parent-_bf -1; } else if (bf -1) { subR-_bf 1; } else if (bf 0) { ; } else { assert(false); } } void _InOredr(Node* root)const { if (root nullptr) return; _InOredr(root-_left); cout root-_kv.second :root-_kv.secondendl; _InOredr(root-_right); } int _IsAVLTree(Node* root)const { if (root nullptr) { return 0; } int left _IsAVLTree(root-_left); int right _IsAVLTree(root-_right); if (left -1 || right -1) { return -1; } if (abs(left - right) 1 || root-_bf ! right - left) { return -1; } if (left right) { right left; } return right 1; } int _Height(Node* root)const { if (root nullptr) return 0; int leftH _Height(root-_left); int rightH _Height(root-_right); if (leftH rightH) { rightH leftH; } return rightH 1; } int _Size(Node* root)const { if (root nullptr) return 0; int leftSize _Size(root-_left); int rightSize _Size(root-_right); return leftSize rightSize1; } Node* _root nullptr; };Part9.2. 测试#include头.h void test() { const int N 1000; vectorint arr; arr.reserve(N); srand(time(0)); for (int i 0; i N; i) { arr.push_back(rand()i); } //int arr[] { 54,0,55,16,5,4,29,38,22,14 }; AVLTreeint, int aaa; for (auto e : arr) { aaa.insert({e,e}); } for (auto e : arr) { aaa.erase(e); aaa.InOrder(); aaa.IsAVLTree(); cout -------------------------------------------------------------- endl; } } int main() { test(); }Part10. 结语这篇文章我们认识到了AVL树的实现接下来小编也会带来更复杂的红黑树的讲解敬请期待~最后祝大家可以春风得意马蹄疾一日看尽长安花最后的最后要是觉得本文还可以的话可以点点赞关注小编一波谢谢大家~

相关新闻

设计模式架构设计实践

设计模式架构设计实践

2026/7/7 23:17:12

设计模式架构设计实践在软件工程领域,设计模式与架构设计是构建可维护、可扩展、高可用软件系统的两大基石。它们并非孤立存在,而是相辅相成,共同指导开发者从微观的代码结构到宏观的系统蓝图进行高质量设计。本文将深入探讨设计模式如何融入…

RAG 检索增强生成的 Java 后端一站式集成方案

RAG 检索增强生成的 Java 后端一站式集成方案

2026/7/7 23:17:12

RAG 检索增强生成的 Java 后端一站式集成方案 一、当大模型的"知识截止日期"撞上你的业务需求 大模型的两大原生局限——知识截止日期和幻觉问题,使得直接使用通用模型处理企业内部知识场景几乎不可行。RAG(Retrieval-Augmented Generation&am…

深入理解Web

深入理解Web

2026/7/7 23:17:12

深入理解Web:连接世界的无形网络在当今时代,“Web”一词早已超越其字面含义,成为现代社会不可或缺的数字基础设施。它不仅是网页的集合,更是一个复杂而精妙的生态系统,承载着信息、商业、社交与文化的全球性流动。深入…

ObjToSchematic:将3D模型智能转换为Minecraft建筑的完整指南

ObjToSchematic:将3D模型智能转换为Minecraft建筑的完整指南

2026/7/8 11:58:22

ObjToSchematic:将3D模型智能转换为Minecraft建筑的完整指南 【免费下载链接】ObjToSchematic A tool to convert 3D models into Minecraft formats such as .schematic, .litematic, .schem and .nbt 项目地址: https://gitcode.com/gh_mirrors/ob/ObjToSchemat…

对讲机频率规划与信道管理实操科普 哈尔滨政企通信有序应用指南

对讲机频率规划与信道管理实操科普 哈尔滨政企通信有序应用指南

2026/7/8 11:58:22

在哈尔滨及黑龙江全省政企、物业、市政、工矿、林区日常工作中,无线对讲机的通信质量,不仅取决于设备硬件性能,更依托科学的频率规划与信道管理。很多单位长期使用默认通用频率,未做专属信道划分与频段优化,极易出现同…

【Bug已解决】Claude Code --model flag not working / Wrong model in use — Claude Code 模型切换失效解决方案

【Bug已解决】Claude Code --model flag not working / Wrong model in use — Claude Code 模型切换失效解决方案

2026/7/8 11:58:22

【Bug已解决】Claude Code --model flag not working / Wrong model in use — Claude Code 模型切换失效解决方案 1. 问题描述 使用 --model 参数或 /model 命令切换模型时,Claude Code 仍然使用旧模型: # --model 参数不生效 $ claude --model sonnet …

基于ICM-42605和PIC18F26J11的6DOF运动追踪系统设计

基于ICM-42605和PIC18F26J11的6DOF运动追踪系统设计

2026/7/8 11:58:22

1. 项目背景与核心需求解析 在当今的智能硬件和物联网领域,精确追踪物体在三维空间中的运动和方向已成为许多应用的基础需求。无论是无人机飞控、VR/AR设备交互,还是工业机器人末端执行器的精确定位,都需要实时获取物体的6自由度(…

服装店想少压货,先算清这笔库存账

服装店想少压货,先算清这笔库存账

2026/7/8 11:58:22

做服装店的老板,几乎都经历过压货带来的焦虑。新款上市前信心满满,结果卖不动,库存堆了一屋子;好不容易等到季末促销,又发现热卖的货早早断码,补单又来不及。压货,本质上是库存计划和销售节奏没…

L9958与PIC18F97J94组合在电机控制中的优势与实践

L9958与PIC18F97J94组合在电机控制中的优势与实践

2026/7/8 11:48:22

1. 为什么选择L9958与PIC18F97J94组合在电机控制领域,芯片选型直接决定了系统性能上限。L9958作为意法半导体(ST)推出的多通道电机驱动芯片,其核心优势在于集成了4个独立的H桥驱动器,每个通道可提供高达1.5A的持续输出电流。这种设计允许单个…

解锁AMD Ryzen处理器深层性能:SMU Debug Tool完全指南

解锁AMD Ryzen处理器深层性能:SMU Debug Tool完全指南

2026/7/8 0:44:47

解锁AMD Ryzen处理器深层性能:SMU Debug Tool完全指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://gi…

6个月转型AI工程师:实战路径与核心技能

6个月转型AI工程师:实战路径与核心技能

2026/7/8 6:29:42

1. 项目概述:6个月转型AI工程师的可行性路径在2023年大模型技术爆发的背景下,AI工程师岗位需求同比增长217%(LinkedIn数据)。不同于传统算法工程师需要3-5年培养周期,现代AI工程师更侧重工程化落地能力。我在硅谷科技公…

YOLOv5模型剪枝与量化实战:边缘设备部署优化

YOLOv5模型剪枝与量化实战:边缘设备部署优化

2026/7/7 13:20:59

1. 项目背景与核心价值在计算机视觉领域,YOLOv5因其出色的实时检测性能成为工业界宠儿。但当我们尝试将其部署到边缘设备(如树莓派、Jetson Nano或手机终端)时,立刻会遇到两个致命问题:模型体积庞大(原始YO…

Qwen Code+Obsidian构建可执行的AI时代认知操作系统

Qwen Code+Obsidian构建可执行的AI时代认知操作系统

2026/7/8 0:07:15

1. 项目概述:这不是又一个笔记软件教程,而是一套可复用的“认知操作系统”搭建逻辑你有没有试过,在读完Andrej Karpathy那篇著名的《Software 2.0》之后,满脑子都是“神经网络即代码”的震撼,但合上网页,打…

校园服饰细分赛道测算程序,学生平价国风,机能穿搭市场规模预估。

校园服饰细分赛道测算程序,学生平价国风,机能穿搭市场规模预估。

2026/7/8 0:07:15

校园服饰细分赛道测算程序(Python)——学生平价国风 & 机能穿搭市场规模预估(TAM / SAM / SOM)一、实际应用场景描述(真实业务抽象)在《时尚产业与品牌创新》课程中,细分市场切入&#xff0…

Visual C++运行库完整解决方案:告别软件兼容性问题

Visual C++运行库完整解决方案:告别软件兼容性问题

2026/7/8 0:07:15

Visual C运行库完整解决方案:告别软件兼容性问题 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾为打开游戏时弹出的"DLL缺失"错误…