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

C++ AVL树的实现

在上一篇博客我们学习了二叉搜索树的实现,现在我们开始手动实现AVL树。

二叉搜索树-CSDN博客

1.AVL树的概念

AVL树是最先发明的⾃平衡⼆叉查找树,AVL是⼀颗空树,或者具备下列性质的⼆叉搜索树:它的左右⼦树都是AVL树,且左右⼦树的⾼度差的绝对值不超过1。AVL树是⼀颗⾼度平衡搜索⼆叉树,通过控制⾼度差去控制平衡。
AVL树实现这⾥我们引⼊⼀个平衡因⼦(balance factor)的概念,每个结点都有⼀个平衡因⼦,任何结点的平衡因⼦等于右⼦树的⾼度减去左⼦树的⾼度,也就是说任何结点的平衡因⼦等于0/1/-1,AVL树并不是必须要平衡因⼦,但是有了平衡因⼦可以更⽅便我们去进⾏观察和控制树是否平衡,就像⼀个⻛向标⼀样。
AVL树整体结点数量和分布和完全⼆叉树类似,⾼度可以控制在logN ,那么增删查改的效率也可以控制在 O(logN ),相⽐⼆叉搜索树有了本质的提升。

这里我们展示了一棵树的平衡因子(右子树的高度-左子树的高度) 

当平衡因子变成2之后说明该树已经不平衡了,我们AVL树的目的就是不仅要让该树是二叉搜索树,还要平衡。

2、AVL树的实现

2.1AVL树的结构

结合我们二叉搜索树的部分,这里我们节点的结构需要使用KV结构再加上一个parent的节点(方便寻找父节点,这里方便之后旋转的操作和理解),再加上一个平衡因子。

#pragma oncetemplate<class K,class V>
struct AVLTreeNode
{typedef AVLTreeNode Node;pair<K, V> _kv;Node<K, V>* _left;Node<K, V>* _right;Node<K, V>* _parent;int _bf;AVLTreeNode(const pair<K,V>& kv):_kv(kv),_left(nullptr), _right(nullptr), _parent(nullptr), _bf(0){}
};template<class K,class V>
class AVLTree
{typedef AVLTreeNode Node;
public:private:Node<K,V>* _root=nullptr;
};

2.2AVL树的插入

2.2.1插入的大概流程

1.首先因为AVL树要满足二叉搜索树,所以我们可以按照二叉搜索树那部分先来写。

2.新增节点后根据不同的情况更新平衡因子。

3.根据平衡因子做旋转调整。

2.2.2平衡因子的更新

更新原则:
• 平衡因⼦ = 右⼦树⾼度-左⼦树⾼度
• 只有⼦树⾼度变化才会影响当前结点平衡因⼦。
• 插⼊结点,会增加⾼度,所以新增结点在parent的右⼦树,parent的平衡因⼦++,新增结点在parent的左⼦树,parent平衡因⼦--
• parent所在⼦树的⾼度是否变化决定了是否会继续往上更新

更新停⽌条件:有三种情况

• 更新后parent的平衡因⼦等于0,更新中parent的平衡因⼦变化为-1->0 或者 1->0,说明更新前parent⼦树⼀边⾼⼀边低,新增的结点插⼊在低的那边,插⼊后parent所在的⼦树⾼度不变,不会影响parent的⽗亲结点的平衡因⼦,更新结束。


• 更新后parent的平衡因⼦等于1 或 -1,更新前更新中parent的平衡因⼦变化为0->1 或者 0->-1,说明更新前parent⼦树两边⼀样⾼,新增的插⼊结点后,parent所在的⼦树⼀边⾼⼀边低,parent所在的⼦树符合平衡要求,但是⾼度增加了1,会影响parent的⽗亲结点的平衡因⼦,所以要继续向上更新。


• 更新后parent的平衡因⼦等于2 或 -2,更新前更新中parent的平衡因⼦变化为1->2 或者 -1->-2,说明更新前parent⼦树⼀边⾼⼀边低,新增的插⼊结点在⾼的那边,parent所在的⼦树⾼的那边更⾼了,破坏了平衡,parent所在的⼦树不符合平衡要求,需要旋转处理,旋转的⽬标有两个:1、把parent⼦树旋转平衡。2、降低parent⼦树的⾼度,恢复到插⼊结点以前的⾼度。所以旋转后也不需要继续往上更新,插⼊结束。


• 不断更新,更新到根,跟的平衡因⼦是1或-1也停⽌了。

2.2.3插入和更新平衡因子的实现

	bool Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* parent=nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_kv.first > kv.first){cur = cur->_left;}else if (cur->_kv.first < kv.first){cur = cur->_right;}else{return false;}}cur=new Node(kv);if (kv.first > parent->_kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//更新平衡因子while(parent){if (cur==parent->_right)parent->_bf++;else {parent->_bf--;}if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}else if (parent->_bf == 0){break;}else{//旋转}}}

2.3  旋转

2.3.1 旋转的原则

1. 保持搜索树的规则
2. 让旋转的树从不满⾜变平衡,其次降低旋转树的⾼度
旋转总共分为四种,左单旋/右单旋/左右双旋/右左双旋。

2.3.2 右单旋

• 本图1展⽰的是10为根的树,有a/b/c抽象为三棵⾼度为h的⼦树(h>=0),a/b/c均符合AVL树的要
求。10可能是整棵树的根,也可能是⼀个整棵树中局部的⼦树的根。这⾥a/b/c是⾼度为h的⼦树,
是⼀种概括抽象表⽰,他代表了所有右单旋的场景,实际右单旋形态有很多种,具体图2/图3/图4/
图5进⾏了详细描述。
• 在a⼦树中插⼊⼀个新结点,导致a⼦树的⾼度从h变成h+1,不断向上更新平衡因⼦,导致10的平
衡因⼦从-1变成-2,10为根的树左右⾼度差超过1,违反平衡规则。10为根的树左边太⾼了,需要
往右边旋转,控制两棵树的平衡。
• 旋转核⼼步骤,因为5 < b⼦树的值 < 10,将b变成10的左⼦树,10变成5的右⼦树,5变成这棵树新的根,符合搜索树的规则,控制了平衡,同时这棵的⾼度恢复到了插⼊之前的h+2,符合旋转原
则。如果插⼊之前10整棵树的⼀个局部⼦树,旋转后不会再影响上⼀层,插⼊结束了。

void RotateR(Node* parent)
{Node* parentL = parent->_left;Node* parentLR = parentL->_right;Node* parentPa = parent->_parent;if (parentPa){if (parent == parentPa->_left)parentPa->_left = parentL;elseparentPa->_right = parentL;}if(parentLR)parentLR->_parent = parent;parent->_parent = parentL;parent->_left = parentLR;parentL->_right = parent;parentL->_parent = parentPa;//更新平衡因子parent->_bf = 0;parentL->_bf = 0;
}

2.3.3 左单旋

与右单旋同理,不过是换了一个方向。

• 本图6展⽰的是10为根的树,有a/b/c抽象为三棵⾼度为h的⼦树(h>=0),a/b/c均符合AVL树的要
求。10可能是整棵树的根,也可能是⼀个整棵树中局部的⼦树的根。这⾥a/b/c是⾼度为h的⼦树,
是⼀种概括抽象表⽰,他代表了所有右单旋的场景,实际右单旋形态有很多种,具体跟上⾯左旋类
似。


• 在a⼦树中插⼊⼀个新结点,导致a⼦树的⾼度从h变成h+1,不断向上更新平衡因⼦,导致10的平
衡因⼦从1变成2,10为根的树左右⾼度差超过1,违反平衡规则。10为根的树右边太⾼了,需要往
左边旋转,控制两棵树的平衡。


• 旋转核⼼步骤,因为10 < b⼦树的值 < 15,将b变成10的右⼦树,10变成15的左⼦树,15变成这棵树新的根,符合搜索树的规则,控制了平衡,同时这棵的⾼度恢复到了插⼊之前的h+2,符合旋转原则。如果插⼊之前10整棵树的⼀个局部⼦树,旋转后不会再影响上⼀层,插⼊结束了。

void RotateL(Node* parent)
{Node* parentR = parent->_right;Node* parentRL = parentR->_left;Node* parentPa = parent->_parent;if (parentPa){if (parent == parentPa->_left)parentPa->_left = parentR;elseparentPa->_right = parentR;}if(parentRL)parentRL->_parent = parent;parent->_parent = parentR;parent->_right = parentRL;parentR->_parent = parentPa;parentR->_left = parent;//更新平衡因子parent->_bf = 0;parentR->_bf = 0;}

2.3.3 左右双旋

还是拿出抽象图。左单旋和右单旋是针对图中a增加,c增加的话其实并不影响,那么如果是b增加的场景呢,这是一个右单旋或者左单旋就不够看了。

通过图可以看到,左边⾼时,如果插⼊位置不是在a⼦树,⽽是插⼊在b⼦树,b⼦树⾼度从h变 成h+1,引发旋转,右单旋⽆法解决问题,右单旋后,我们的树依旧不平衡。右单旋解决的纯粹的左边 ⾼,但是插⼊在b⼦树中,10为跟的⼦树不再是单纯的左边⾼,对于10是左边⾼,但是对于5是右边⾼,需要⽤两次旋转才能解决,以5为旋转点进⾏⼀个左单旋,以10为旋转点进⾏⼀个右单旋,这棵树这棵树就平衡了。

• 图分别为左右双旋中h==0和h==1具体场景分析,下⾯我们将a/b/c⼦树抽象为⾼度h的AVL
⼦树进⾏分析,另外我们需要把b⼦树的细节进⼀步展开为8和左⼦树⾼度为h-1的e和f⼦树,因为
我们要对b的⽗亲5为旋转点进⾏左单旋,左单旋需要动b树中的左⼦树。b⼦树中新增结点的位置
不同,平衡因⼦更新的细节也不同,通过观察8的平衡因⼦不同,这⾥我们要分三个场景讨论。
• 场景1:h >= 1时,新增结点插⼊在e⼦树,e⼦树⾼度从h-1并为h并不断更新8->5->10平衡因⼦,引发旋转,其中8的平衡因⼦为-1,旋转后8和5平衡因⼦为0,10平衡因⼦为1。
• 场景2:h >= 1时,新增结点插⼊在f⼦树,f⼦树⾼度从h-1变为h并不断更新8->5->10平衡因⼦,引发旋转,其中8的平衡因⼦为1,旋转后8和10平衡因⼦为0,5平衡因⼦为-1。
• 场景3:h == 0时,a/b/c都是空树,b⾃⼰就是⼀个新增结点,不断更新5->10平衡因⼦,引发旋
转,其中8的平衡因⼦为0,旋转后8和10和5平衡因⼦均为0。

void RotateLR(Node* parent)
{int bf = parent->_left->_right->_bf;Node* parentL = parent->_left;Node* parentLR = parentL->_right;RotateL(parent->_left);RotateR(parent);//更新平衡因子if (bf == 1){parentL->_bf = -1;parent->_bf = 0;parentLR->_bf = 0;}else if (bf == -1){parentL->_bf = 0;parent->_bf = 1;parentLR->_bf = 0;}else if (bf == 0){parentL->_bf = 0;parent->_bf = 0;parentLR->_bf = 0;}else{assert(1);}
}

2.3.4 右左双旋

• 跟左右双旋类似,下⾯我们将a/b/c⼦树抽象为⾼度h的AVL⼦树进⾏分析,另外我们需要把b⼦树的细节进⼀步展开为12和左⼦树⾼度为h-1的e和f⼦树,因为我们要对b的⽗亲15为旋转点进⾏右单
旋,右单旋需要动b树中的右⼦树。b⼦树中新增结点的位置不同,平衡因⼦更新的细节也不同,通
过观察12的平衡因⼦不同,这⾥我们要分三个场景讨论。


• 场景1:h >= 1时,新增结点插⼊在e⼦树,e⼦树⾼度从h-1变为h并不断更新12->15->10平衡因
⼦,引发旋转,其中12的平衡因⼦为-1,旋转后10和12平衡因⼦为0,15平衡因⼦为1。
• 场景2:h >= 1时,新增结点插⼊在f⼦树,f⼦树⾼度从h-1变为h并不断更新12->15->10平衡因⼦,
引发旋转,其中12的平衡因⼦为1,旋转后15和12平衡因⼦为0,10平衡因⼦为-1。
比特就业课
• 场景3:h == 0时,a/b/c都是空树,b⾃⼰就是⼀个新增结点,不断更新15->10平衡因⼦,引发旋
转,其中12的平衡因⼦为0,旋转后10和12和15平衡因⼦均为0。

void RotateR(Node* parent)
{Node* parentL = parent->_left;Node* parentLR = parentL->_right;Node* parentPa = parent->_parent;if (parentPa){if (parent == parentPa->_left)parentPa->_left = parentL;elseparentPa->_right = parentL;}if(parentLR)parentLR->_parent = parent;parent->_parent = parentL;parent->_left = parentLR;parentL->_right = parent;parentL->_parent = parentPa;//更新平衡因子parent->_bf = 0;parentL->_bf = 0;
}

2.4 AVL树的查找

那⼆叉搜索树逻辑实现即可,搜索效率为 O(logN)

Node* Find(const K& key)
{Node * cur=_root;while (cur){if (cur->_kv.first > key){cur = cur->_left;}else if (cur->_kv.first < key){cur = cur->_right;}else{return cur;}}return nullptr;
}

2.5 AVL树插入的检测

我们实现的AVL树是否合格,我们通过检查左右⼦树⾼度差的的程序进⾏反向验证,同时检查⼀下结点的平衡因⼦更新是否出现了问题。
结合检测所需要的代码,全部代码如下:
#include<iostream>
#include<set>
#include<map>
#include <utility>
using namespace std;
#include<assert.h>
#include<vector>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;AVLTreeNode(const pair<K,V>& kv):_kv(kv),_left(nullptr), _right(nullptr), _parent(nullptr), _bf(0){}
};template<class K,class V>
class AVLTree
{typedef AVLTreeNode<K,V> Node;
public:void InOrder(){_InOrder(_root);}void _InOrder(const Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << ' ';_InOrder(root->_right);}bool Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* parent=nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_kv.first > kv.first){cur = cur->_left;}else if (cur->_kv.first < kv.first){cur = cur->_right;}else{return false;}}cur=new Node(kv);if (kv.first > parent->_kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//更新平衡因子while(parent){if (cur==parent->_right)parent->_bf++;else {parent->_bf--;}if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}else if (parent->_bf == 0){break;}else{//旋转if (parent->_bf == -2 && parent->_left->_bf == -1){//右单旋RotateR(parent);}else if (parent->_bf == 2 && parent->_right->_bf==1){//左单旋RotateL(parent);}else if (parent->_bf == -2 && parent->_left->_bf == 1){//左右双旋RotateLR(parent);}else if (parent->_bf == 2 && parent->_right->_bf == -1){//右左双旋RotateRL(parent);}else{assert(1);}return true;}}return true;}void RotateRL(Node* parent){int bf = parent->_right->_left->_bf;Node* parentR = parent->_right;Node* parentRL = parentR->_left;RotateR(parent->_right);RotateL(parent);//更新平衡因子if (bf == 1){parent->_bf = -1;parentR->_bf = 0;parentRL = 0;}else if (bf == -1){parent->_bf = 0;parentR->_bf = 1;parentRL = 0;}else if (bf == 0){parent->_bf = 0;parentR->_bf = 0;parentRL = 0;}else{assert(1);}}void RotateLR(Node* parent){int bf = parent->_left->_right->_bf;Node* parentL = parent->_left;Node* parentLR = parentL->_right;RotateL(parent->_left);RotateR(parent);//更新平衡因子if (bf == 1){parentL->_bf = -1;parent->_bf = 0;parentLR->_bf = 0;}else if (bf == -1){parentL->_bf = 0;parent->_bf = 1;parentLR->_bf = 0;}else if (bf == 0){parentL->_bf = 0;parent->_bf = 0;parentLR->_bf = 0;}else{assert(1);}}void RotateR(Node* parent){Node* parentL = parent->_left;Node* parentLR = parentL->_right;Node* parentPa = parent->_parent;if (parentPa){if (parent == parentPa->_left)parentPa->_left = parentL;elseparentPa->_right = parentL;}if(parentLR)parentLR->_parent = parent;parent->_parent = parentL;parent->_left = parentLR;parentL->_right = parent;parentL->_parent = parentPa;//更新平衡因子parent->_bf = 0;parentL->_bf = 0;}void RotateL(Node* parent){Node* parentR = parent->_right;Node* parentRL = parentR->_left;Node* parentPa = parent->_parent;if (parentPa){if (parent == parentPa->_left)parentPa->_left = parentR;elseparentPa->_right = parentR;}if(parentRL)parentRL->_parent = parent;parent->_parent = parentR;parent->_right = parentRL;parentR->_parent = parentPa;parentR->_left = parent;//更新平衡因子parent->_bf = 0;parentR->_bf = 0;}Node* Find(const K& key){Node * cur=_root;while (cur){if (cur->_kv.first > key){cur = cur->_left;}else if (cur->_kv.first < key){cur = cur->_right;}else{return cur;}}return nullptr;}int Height(Node* root){return _Height(_root);}int _Height(Node* root){if (root == nullptr)return 0;int heightleft = _Height(root->_left);int heightright = _Height(root->_right);return heightleft > heightright ? heightleft + 1 : heightright + 1;}bool IsBalanceTree(){return _IsBalanceTree(_root);}bool _IsBalanceTree(Node* root){if (root == nullptr)return true;int heightleft = _Height(root->_left);int heightright = _Height(root->_right);int diff = heightright - heightleft;if (abs(diff) >= 2){cout << "高度差异常" << endl;return false;}if (root->_bf != diff){cout << "平衡因子异常" << endl;return false;}return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);}
private:Node* _root=nullptr;
};void TestAVLTree1()
{AVLTree<int, int> t;// 常规的测试?例//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };// 特殊的带有双旋场景的测试?例int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };for (auto e : a){t.Insert({ e, e });}t.InOrder();cout << t.IsBalanceTree() << endl;
}void TestAVLTree2()
{const int N = 100000;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; i++){v.push_back(rand()+ i);}size_t begin2 = clock();AVLTree<int, int> t;for (auto e : v){t.Insert(make_pair(e, e));}size_t end2 = clock();size_t begin1 = clock();//确定在的值for (auto e : v){t.Find(e);}//随机值/*for (size_t i = 0; i < N; i++){t.Find((rand() + i));}*/size_t end1 = clock();cout << "Find:" << end1 - begin1 << endl;
}int main()
{TestAVLTree1();TestAVLTree2();return 0;
}

2.6 AVL树的删除

学习AVL树我们的主要目的是学会旋转的逻辑,删除与插入的逻辑其实差不了很多,有兴趣的小伙伴可以自行编写,或者看以下博客:

AVL树图解(插入与删除)_avl树的删除-CSDN博客

 

相关文章:

C++ AVL树的实现

在上一篇博客我们学习了二叉搜索树的实现&#xff0c;现在我们开始手动实现AVL树。 二叉搜索树-CSDN博客 1.AVL树的概念 AVL树是最先发明的⾃平衡⼆叉查找树&#xff0c;AVL是⼀颗空树&#xff0c;或者具备下列性质的⼆叉搜索树&#xff1a;它的左右⼦树都是AVL树&#xff0c…...

多视觉编码器协同与高低分辨率特征融合技术综述

本文主要介绍&#xff08;论文发表时间&#xff1a;24.03-25.01&#xff09;在多模态中使用多个视觉编码器如何进行特征融合操作&#xff08;之所以用多视觉编码器&#xff0c;主要用途在于&#xff1a;有些视觉编码器可能只能提取到部分信息&#xff0c;就想通过另外一个编码器…...

力扣4-最长公共前缀

一.题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1&#xff1a; 输入&#xff1a;strs ["flower","flow","flight"] 输出&#xff1a;"fl"示例 2&…...

贪心算法-860.柠檬水找零-力扣(LeetCode)

一、题目解析 我们需要注意我们是没有初始零钱的&#xff0c;所以当第一个顾客支付10或20时&#xff0c;无法找零此时返回false。 二、算法解析 根据贪心算法的解决方式&#xff0c;我们需要先把解决该问题分解为若干步。 首先对于顾客支付的钱共有三种&#xff0c;5&#xf…...

Kubernetes学习笔记-配置Service对接第三方访问

在Kubernetes中配置Service对接第三方访问&#xff0c;可以选择以下方案实现&#xff1a; ExternalName Service&#xff08;基于DNS别名&#xff09;‌ 适用场景‌&#xff1a;外部服务必须有固定域名Service配置文件如下&#xff1a; apiVersion: v1 kind: Service metadata…...

pikachu靶场-敏感信息泄露

一、敏感信息泄露的危害 1. 个人隐私与数据安全 身份盗窃&#xff1a;泄露个人身份信息&#xff08;如姓名、身份证号、手机号&#xff09;可被用于诈骗、冒名开户等犯罪活动。账户劫持&#xff1a;暴露用户账号密码、邮箱等凭证&#xff0c;导致社交媒体、银行账户被非法登录。…...

ppt章节页怎么做好看?ppt章节页模板

ppt章节页怎么做好看&#xff1f;ppt章节页怎么排版&#xff1f;ppt章节页模板: PPT章节_模板素材_PPT模板_ppt素材_免抠图片_AiPPTer...

ubuntu扩展逻辑卷并调整文件系统大小步骤

安装好ubuntu如果没有调整磁盘空间,一般默认给你100G的空间,在用完时再调整也还来得及,下面是 ubuntu扩展逻辑卷并调整文件系统大小步骤&#xff1a; 1. 扩展逻辑卷 运行以下命令来扩展逻辑卷 /dev/ubuntu-vg/ubuntu-lv&#xff0c;使其使用卷组中所有未分配的空间&#xff…...

2.脚本文件初识

—>1.Makefile—自动化构建和管理项目的文件见这篇<— 1.编程语言 编程语言分为2类&#xff0c;一类是编译型语言&#xff0c;将源文件经过编译得到可执行文件&#xff0c;该执行文件可以在特定平台上运行&#xff0c;其他平台则不行&#xff0c;因此是不跨平台的编程语…...

FastAPI + Redis Pub/Sub + WebSocket 组合解决方案的详细介绍

以下是对 FastAPI Redis Pub/Sub WebSocket 组合解决方案的详细介绍&#xff0c;涵盖技术原理、实现步骤、协作流程和适用场景。 1. 技术概述 1.1 FastAPI 特性&#xff1a;基于 Python 的现代异步框架&#xff0c;支持 async/await&#xff0c;性能高效&#xff0c;适合高…...

泛型的诗意——深入C++模板的艺术与科学(模版进阶)

前言&#xff1a; 在之前&#xff0c;小编讲述了模版的初阶内容&#xff0c;当时小编讲述了模版的书写&#xff0c;方便之后容器的讲解以及模拟实现&#xff0c;现在小编已经带领各位学习了很多容器&#xff0c;模版初阶的知识已经用的很多了&#xff0c;今天小编讲述一下全新的…...

【极致版】华为云Astro轻应用抽取IoTDA影子设备参数生成表格页面全流程

做份极致详细Astro调取iotda影子设备数据的操作手册&#xff0c;每一步都分成&#xff1a; 要进入哪个界面 点哪个按钮 要填什么内容&#xff08;样例&#xff09; 如果出错怎么办 填写示例 完全对应你这个需求&#xff1a;Astro轻应用抽取IoTDA影子设备数据&#xff0c;…...

业务中台与数据中台:企业数字化转型的核心引擎

前言&#xff1a;在当今数字化浪潮下&#xff0c;企业为了提升运营效率、加速创新步伐并更好地适应市场变化&#xff0c;业务中台与数据中台应运而生&#xff0c;成为企业架构中的关键组成部分。本文将深入探讨业务中台和数据中台的简介、发展史、技术流环节以及在实际生产中的…...

前端分页与瀑布流最佳实践笔记 - React Antd 版

前端分页与瀑布流最佳实践笔记 - React Antd 版 1. 分页与瀑布流对比 分页&#xff08;Pagination&#xff09;瀑布流&#xff08;Infinite Scroll&#xff09;展示方式按页分批加载&#xff0c;有明确页码控件滚动到底部时自动加载更多内容&#xff0c;无明显分页用户控制用…...

【网络原理】从零开始深入理解TCP的各项特性和机制.(三)

上篇介绍了网络原理传输层TCP协议的知识,本篇博客给大家带来的是网络原理剩余的内容, 总体来说,这部分内容没有上两篇文章那么重要,本篇知识有一个印象即可. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分…...

MySQL:13.用户管理

13. 用户管理 如果我们只能使用root用户&#xff0c;这样存在安全隐患。这时&#xff0c;就需要使用MySQL的用户管理。 13.1 用户 13.1.1 用户信息 MySQL中的用户&#xff0c;都存储在系统数据库mysql的user表中 mysql> use mysql; Database changed mysql> select h…...

leetcode0103. 二叉树的锯齿形层序遍历-medium

1 题目&#xff1a;二叉树的锯齿形层序遍历 官方标定难度&#xff1a;中 给你二叉树的根节点 root &#xff0c;返回其节点值的 锯齿形层序遍历 。&#xff08;即先从左往右&#xff0c;再从右往左进行下一层遍历&#xff0c;以此类推&#xff0c;层与层之间交替进行&#xf…...

【Go语言】ORM(对象关系映射)库

github.com/jinzhu/gorm 是 Go 语言中一个非常流行的 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;用于简化与关系型数据库的交互。以下是关于它的关键信息&#xff1a; 核心特点 全功能 ORM 支持主流数据库&#xff1a;MySQL、PostgreSQL、SQLite、SQL Server 等。…...

Java : GUI

AWT 初始化界面 直接封装起来&#xff1a; panel 的添加 布局 流式布局,控制按钮的位置 东西南北中布局 网格布局 frame.pack();java函数&#xff0c;会自动选择最优的布局 事件监听 给按钮添加 添加文本 画笔 鼠标监听 键盘监听 JDialog”弹窗 默认有关闭事件 标签&#…...

ipa包安装到apple手机上

获ipa包的方式 ipatool 下载appStore的ipa包-CSDN博客 方式一&#xff1a;巨魔商店 原理是利用apple的漏洞&#xff0c;但是有低版本的系统要求 TrollStore - Always Sideload Any IPAs For FreeTrollStore - The ultimate jailbreak app for iOS. Permanently install any …...

JavaScript输出数据的方法

1. console.log() console.log()是最常用的方法之一&#xff0c;用于在浏览器的控制台&#xff08;Console&#xff09;中输出信息。这对于调试和查看变量的值非常有用。 console.log("Hello, world!");2. alert() alert()方法会弹出一个带有指定消息和确定按钮的警告…...

操作系统:计算机世界的基石与演进

一、操作系统的本质与核心功能 操作系统如同计算机系统的"总管家"&#xff0c;在硬件与应用之间架起关键桥梁。从不同视角观察&#xff0c;其核心功能呈现多维价值&#xff1a; 硬件视角的双重使命&#xff1a; 硬件管理者&#xff1a;通过内存管理、进程调度和设…...

FFmpeg之三 录制音频并保存, API编解码从理论到实战

在学习FFmpeg的时候&#xff0c;想拿demo来练习&#xff0c;官方虽有示例&#xff0c;但更像是工具演示&#xff0c;新手不好掌握&#xff0c;在网上找不到有文章&#xff0c;能给出完整的示例和关键点的分析说明&#xff0c;一步一个错误&#xff0c;慢慢啃过来的&#xff0c;…...

幂等性处理解决方案实战示例

幂等性处理解决方案实战示例 幂等性是指对同一个操作执行一次或多次&#xff0c;产生的结果是相同的。在分布式系统、网络请求和金融交易等场景中&#xff0c;幂等性设计至关重要。下面我将介绍几种常见的幂等性处理方案及其实战示例。 1. 唯一标识符方案 原理&#xff1a;为…...

华为仓颉编程语言的实际用法与使用领域详解

华为仓颉编程语言的实际用法与使用领域详解 一、语言概述与核心特性 华为仓颉编程语言是面向万物智联时代的系统级编程语言,其核心特性包括: 三重内存安全机制:所有权系统 + 引用检查 + 硬件辅助防护零成本抽象:高级语法不牺牲底层性能全场景支持:从嵌入式设备到量子计算…...

JavaEE-多线程实战01

Java 多线程入门&#xff1a;第一个多线程程序 在 Java 中&#xff0c;多线程编程是非常重要的一部分。本篇文章将通过示例&#xff0c;带你快速了解如何创建第一个多线程程序&#xff0c;并深入分析其运行机制。 1. 创建一个线程类并继承 Thread 在 Java 中&#xff0c;我们…...

当AI浏览器和AI搜索替代掉传统搜索份额时,老牌的搜索引擎市场何去何从。

AI搜索与传统搜索优劣势分析 AI搜索优势 理解和处理查询方式更智能&#xff1a;利用自然语言处理&#xff08;NLP&#xff09;和机器学习技术&#xff0c;能够更好地理解用户的意图和上下文&#xff0c;处理复杂的问答、长尾问题以及多轮对话&#xff0c;提供更为精准和相关的…...

大模型——Spring.new快速构建AI驱动的定制化商业应用

大模型——Spring.new快速构建AI驱动的定制化商业应用 Spring.new 是一个基于人工智能的在线平台,专注于帮助营销经理和产品经理快速构建定制化工作流和小型应用。它通过自然语言输入,让用户描述需求,自动生成连接 Notion、Airtable、Slack 等工具的工作流或应用,例如将 F…...

django admin 中更新表数据 之后再将数据返回管理界面

在Django中&#xff0c;更新数据库中的数据并将其重新显示在Django Admin界面上通常涉及到几个步骤。这里我将详细说明如何在Django Admin中更新表数据&#xff0c;并确保更新后的数据能够立即在管理界面上显示。 定义模型 首先&#xff0c;确保你的模型&#xff08;Model&…...

深度理解linux系统—— 进程概念

一、进程 进程&#xff0c;什么是进程&#xff1f; 在课本&#xff0c;教材中是这样描述的&#xff1a;程序的一个执行示例&#xff0c;正在执行的程序&#xff1b; 从内核角度来说&#xff0c;进程就是担当分配系统资源&#xff08;CPU时间&#xff0c;内存&#xff09;的实体…...

【如何使用solidwork编辑结构导入到simscope】

这里写自定义目录标题 欢迎使用Markdown编辑器 欢迎使用Markdown编辑器 To use Simscape Multibody Link, you must install MATLAB and the CAD applications on the same computer. To ensure the successful installation of Simscape Multibody Link, before launching yo…...

Flink 时态维度表 Join 与缓存机制实战

一、引言&#xff1a;为什么需要时态维度表&#xff1f; 在实时数仓建设中&#xff0c;维度表是不可或缺的一环&#xff0c;例如&#xff1a; 风控系统中&#xff0c;用户的风险等级在不同时间可能变化&#xff1b; 营销体系中&#xff0c;商品的促销标签会动态调整&#xff…...

Apache Tomcat 漏洞(CVE-2025-24813)导致服务器面临 RCE 风险

CVE-2025-24813Apache Tomcat 中发现了一个严重安全漏洞,标识为,该漏洞可能导致服务器面临远程代码执行 (RCE)、信息泄露和数据损坏的风险。 此缺陷影响以下版本: Apache Tomcat11.0.0-M1通过11.0.2Apache Tomcat10.1.0-M1通过10.1.34Apache Tomcat9.0.0-M1通过9.0.98了解 …...

来自B站-AI匠的“RAG的prompt设计指南“的部分截图

来自B站-AI匠的“RAG的prompt设计指南“的部分截图 0. 引言1. RAG提示词 - 部分视频截图2. 总结 - 部分视频截图3. 举例 - 部分视频截图 0. 引言 这个文章记录的是B站Up主AI匠关于RAG的prompt设计指南的视频截图。 1. RAG提示词 - 部分视频截图 笔记&#xff1a; Up主推荐Fa…...

【Linux】Centos7 在 Docker 上安装 Redis7.0(最新详细教程)

一、拉取 Redis 镜像 1. 从 阿里云加速器&#xff08;docker hub&#xff09;拉取 redis镜像&#xff0c;选择镜像标签为 7.2.4 docker pull redis:7.2.4 2. 准备 Redis 的配置文件&#xff08;便于后期对配置文件进行修改&#xff09; 3.在服务器上创建需要挂载的文件夹 mk…...

Java使用微信云服务HTTP API操作微信云开发数据库

可以直接用的工具类代码 package com.kstc.qgy.util;import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.kstc.qgy.model.exception.WxException; import com.kstc.qgy.model.service.Limit; imp…...

Linux的权限

目录 1、用户分类 1.1 超级用户(root)和普通用户 1.2 普通<->超级 1.3 sudo 2、文件和目录的权限 2.1 chown&&chgrp 2.1.1 chown 2.1.2 chgrp 2.2 chmod 总结一下&#xff1a; 3、文件和目录的默认权限 4、共享文件 4.1 理解多用户隔离 4.2 /tmp/ 1…...

ACT游戏和MMORPG经济形态区别以及对经济循环的思考

对于原神的明日之后经济形态的不同解析 对于MMORPG游戏来说&#xff0c;如果采用开放市场经济的设计&#xff0c;以明日之后为例&#xff0c;系统产出端为采集、运营活动投放&#xff1b;玩家产出端为交易&#xff1b;消耗端为武器耐久的减少。但我好奇&#xff0c;在ACT游戏里…...

zynq7035的arm一秒钟最多可以支持触发多少次中断

一、概述 1.关于zynq7035的ARM处理器一秒能够支持多少次中断触发&#xff0c;需要综合来考虑。需要确定ARM处理器的参数&#xff0c;目前zynq7000系列&#xff0c;使用的双核Cortex-A9处理器。其中主频大概在500MHZ~1GHZ左右&#xff0c;不同的用户配置的主频可能稍微有差别。 …...

Spring MVC 拦截器教程

一、拦截器核心概念 1.1 拦截器 vs 过滤器 特性过滤器 (Filter)拦截器 (Interceptor)依赖关系Servlet容器Spring MVC框架作用范围所有Web请求Controller请求实现机制Java EE标准Java反射AOP生命周期服务器启动时初始化随Spring容器初始化功能场景字符编码、安全过滤权限校验、…...

【HPC存储性能测试】02-ior带宽性能测试

文章目录 一、前言二、软件安装1、安装依赖2、安装软件 三、参数说明1、mpirun参数2、ior参数 四、测试说明 一、前言 ior introduction | github hpc ior IOR 测试工具使用 POSIX、 MPIIO 或 HDF5接口对并行文件系统进行基准测试 通常使用IOR测试工具时&#xff0c;一般会配合…...

【RabbitMQ】保证消息不丢失

要确保 RabbitMQ 在消费者&#xff08;Python 服务&#xff09;重启或挂掉时消息不丢失&#xff0c;需结合 消息持久化、确认机制&#xff08;ACK&#xff09; 和 死信队列&#xff08;DLX&#xff09; 实现高可靠性&#xff1a; 1. 消息持久化&#xff08;Durability&#xff…...

算法效率的钥匙:从大O看复杂度计算 —— C语言数据结构第一讲

目录 1.数据结构与算法 1.1数据结构介绍 1.2算法介绍 2.算法效率 2.1复杂度 2.1.1时间复杂度 2.1.1.1时间复杂度计算示例1 2.1.1.2时间复杂度计算示例2 2.1.1.3时间复杂度计算示例3 2.1.1.4时间复杂度计算示例4 2.1.1.5时间复杂度计算示例5 2.1.1.6时间复杂度计算示例6…...

AI赋能守护行车安全新防线,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建驾驶车辆场景下驾驶员疲劳分心驾驶行为智能检测预警系统

在当今社会&#xff0c;随着科技生产力的飞速发展&#xff0c;汽车早已成为人们日常出行不可或缺的交通工具。它不仅极大地提高了人们的出行效率&#xff0c;也为生活带来了诸多便利。然而&#xff0c;随着汽车保有量的不断增加&#xff0c;交通安全问题也日益凸显。疲劳驾驶和…...

HNUST湖南科技大学-嵌入式考试选择题题库(109道纠正详解版)

HNUST嵌入式选择题题库 1.下面哪点不是嵌入式操作系统的特点。(B) A.内核精简 B.功能强大 C.专用性强 D.高实时性 解析&#xff1a; 嵌入式操作系统特点是内核精简、专用性强、高实时性&#xff0c;而"功能强大"通常指的是通用操作系统&#x…...

【音视频】SDL事件

SDL 事件 函数 SDL_WaitEvent()&#xff1a; 等待一个事件SDL_PushEvent()&#xff1a; 发送一个事件SDL_PumpEvents()&#xff1a; 将硬件设备产生的事件放入事件队列&#xff0c;用于读取事件&#xff0c;在调用该函数之前&#xff0c;必须调用SDL_PumpEvents搜集键盘等事件…...

[特殊字符]实战:使用 Canal + MQ + ES + Redis + XXL-Job 打造高性能地理抢单系统

&#x1f4da;目录 项目背景 技术栈总览 详细流程分析 3.1 Canal监听MySQL Binlog 3.2 MQ中转传递订单变化 3.3 Elasticsearch存储并查询附近订单 3.4 Redis高性能抢单Lua防止抢单冲突 3.5 XXL-Job定时任务处理 完整系统流程图 总结 一、项目背景 针对类似外卖、跑…...

FPGA基础之基础语法

一、基本模块结构 Verilog 代码以 模块&#xff08;Module&#xff09; 为单位&#xff0c;每个模块对应一个硬件功能单元&#xff08;如逻辑门、寄存器等&#xff09;。 基本格式&#xff1a; module 模块名 (// 输入输出端口声明input 端口1,input 端口2,output 端口3 );…...

影楼精修-皮肤瑕疵祛除算法解析

注意&#xff1a;本文样例图片为了避免侵权&#xff0c;均使用AIGC生成&#xff1b; 顾名思义&#xff0c;皮肤瑕疵祛除旨在祛除人像照片皮肤区域的痘痘/斑点/痣/胎记等瑕疵&#xff1b;当前主流算法方案可分为传统图像处理方法和基于深度学习的方法&#xff0c;本文重点介绍基…...

2025蓝桥杯省赛网络安全组wp

文章目录 黑客密室逃脱ezEvtxflowzipEnigma星际xml解析器EBC-TrainAES-CBC 黑客密室逃脱 提示猜文件名&#xff0c;猜几个常见的&#xff0c;app.py读到源码 这里也是脑抽了一下&#xff0c;把密钥看成1236了。。。卡了五分钟左右&#xff0c;解出来的时候已经降到300多分了&a…...