C++:AVL树

目录

AVL树概念

AVL树的实现

AVL树的节点

AVL树的插入

AVL树的平衡调整

右单旋

左单旋

左右双旋

右左双旋

完整的插入函数

AVL树的查找

AVL树的验证

验证有序

验证平衡

完整代码


AVL树概念

AVL树是一种具有特殊性质的二叉搜索树,AVL树的左右子树也都是AVL树,且左右子树的高度差的绝对值不超过1超过1就说明AVL树失衡,需要调整。AVl树是一颗高度平衡的二叉搜索树,通过高度控制高度差去控制平衡。

AVL树对比二叉搜索树多引入了一个平衡因子的概念,每个节点都有一个平衡因子,任何节点的平衡因子等于右子树的高度减去左子树的高度,所以说平衡因子的取值是0、1和-1

AVL树整体节点和分布与完全二叉树类似高度控制在logN范围内,那么增删查改的效率也可以控制在O(logN),相比二叉搜索树有了本质提升。

以下这棵树就是AVL树。

           

AVL树的实现

AVL树的节点

由于在调整失衡的AVL树时,需要频繁访问父节点,所以我们在定义节点时也需要引入parent指针。

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){}
};

AVL树的插入

向AVL树插入新节点的过程与二叉搜索树的插入类似,但有区别的是,插入新节点后需要更新平衡因子,然后根据平衡因子的情况判断AVL树是否失衡失衡就对AVL树进行调整。

按照平衡因子的计算公式,如果新节点插入到了父亲节点的左边,那么父亲的平衡因子-1,反之,如果插入到右边父亲的平衡因子+1

更新后的平衡因子的情况,可以分为两种:1.平衡因子(从1/-1)变成0。 2.平衡因子(从0)变成1/-1。

情况1就说明已经完成平衡因子的更新了,情况2就还得继续更新,因为当父亲的平衡因子为1/-1时,说明以父亲为根节点的子树高度发生了变化,这样会影响父亲的父亲的平衡因子,所以需要继续往上更新平衡因子。

template<class K, class V>
class AVLTree
{typedef AVLTreeNode 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){parent = cur;if (kv.first > cur->_kv.first)cur = cur->_right;else if (kv.first < cur->_kv.first)cur = cur->_left;elsereturn false;}cur = new Node(kv);//将父节点与新节点链接//判断新节点插入到parent的左边还是右边if (kv.first > parent->_kv.first) //新节点插入到parent的右边parent->_right = cur;elseparent->_left = cur;//更改新节点的父亲指针cur->_parent = parent;//更新平衡因子while (parent){//插入节点后除了对父节点造成影响还可能对祖宗节点造成影响//随着循环进行,cur不一定为新节点//更新父节点的平衡因子if (cur == parent->_left)parent->_bf--;elseparent->_bf++;//检查更新后父亲的平衡因子//_bf为0,说明树还是AVL树,退出循环if (parent->_bf == 0)break;//_bf == 1/-1,说明需要继续向上更新平衡因子else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}//_bf == 2/-2,说明AVL树失衡,需要进行旋转操作else if (parent->_bf == 2 || parent->_bf == -2){//插入后AVl树失衡,需要进行平衡调整}}return true;}private:Node* _root = nullptr;;
};

AVL树的平衡调整

AVL树的调整其实就是对失衡的AVl树进行旋转操作,旋转操作必须保持搜索树的规则让失衡的AVL树变平衡。

旋转操作可以分为4种:右单旋、左单旋、左右双旋和右左双旋。

右单旋

parent->_bf == -2 && cur->_bf == -1时说明AVL树往左倾斜,需要进行右单旋操作。

右单旋其实就是从树的右边将树顺时针旋转。     

 

void RotataR(Node* parent)
{//subL为parent的左孩子节点Node* subL = parent->_left;//subLR为subL的右子节点Node* SubLR = subL->_right;// 将parent与subLR节点进行链接parent->_left = SubLR;//在SubLR的情况下更改,让其指向正确的父亲if (SubLR)SubLR->_parent = parent;//提前记录祖父节点Node* pParent = parent->_parent;//链接subL与parentsubL->_right = parent;parent->_parent = subL;//根据parent是否是根节点进行不同处理if (parent == _root){_root = subL;subL->_parent = nullptr;}else {//将pParent和subL链接//但得先判断parent是pParent的左节点还是右节点if (pParent->_left == parent)pParent->_left = subL;elsepParent->_right = subL;//修改subL的parent指针,让其指向正确的父亲subL->_parent = pParent;}//更新平衡因子subL->_bf = parent->_bf = 0;
}

左单旋

parent->_bf == 2 && cur->_bf == 1时说明AVL树往右倾斜,需要进行左单旋操作。

左单旋其实就是从树的左边将树逆时针旋转。

 

 

void RotateL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* pParent = parent->_parent;subR->_left = parent;parent->_parent = subR;if (parent == _root){_root = subR;subR->_parent = nullptr;}else{if (pParent->_left == parent)pParent->_left = subR;elsepParent->_right = subR;subR->_parent = pParent;}subR->_bf = parent->_bf = 0;
}

左右双旋

parent->_bf == -2 && cur->_bf == 1时,即新节点插入到较高左子树的右侧:先左单旋然后再右单旋。

左右双旋情况比较复杂,如下图。

void RotateLR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;//记录subLR的bf,根据其取值更新左右双旋后各个节点的bfint bf = subLR->_bf;	RotateL(subL);RotateR(parent);subLR->_bf = 0;if (bf == -1){subL->_bf = 0;parent->_bf = 1;}else if (bf == 1){subL->_bf = -1;parent->_bf = 0;}else if (bf == 0){subL->_bf = 0;parent->_bf = 0;}elseassert(false);}

右左双旋

parent->_bf == 2 && cur->_bf == -1时,即新节点插入到较高右子树的左侧:先右单旋然后再左单旋。

右左双旋其实就是左右双旋的另一种情况,我们直接上图解。

 

void RotateRL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);subRL->_bf = 0;if (bf == -1){subR->_bf = 1;parent->_bf = 0;}else if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == 0){subR->_bf = 0;parent->_bf = 0;}elseassert(false);}

完整的插入函数

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 (kv.first > cur->_kv.first)cur = cur->_right;else if (kv.first < cur->_kv.first)cur = cur->_left;elsereturn false;}cur = new Node(kv);//将父节点与新节点链接//判断新节点插入到parent的左边还是右边if (kv.first > parent->_kv.first) //新节点插入到parent的右边parent->_right = cur;elseparent->_left = cur;//更改新节点的父亲指针cur->_parent = parent;//更新平衡因子while (parent){//插入节点后除了对父节点造成影响还可能对祖宗节点造成影响//随着循环进行,cur不一定为新节点//更新父节点的平衡因子if (cur == parent->_left)parent->_bf--;elseparent->_bf++;//检查更新后父亲的平衡因子//_bf为0,说明树还是AVL树,退出循环if (parent->_bf == 0)break;//_bf == 1/-1,说明需要继续向上更新平衡因子else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}//_bf == 2/-2,说明AVL树失衡,需要进行旋转操作else if (parent->_bf == 2 || parent->_bf == -2){//插入后AVl树失衡,需要进行平衡调整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);elseassert(false);break;}elseassert(false);}return true;}

AVL树的查找

AVL树的查找与二叉搜索树是一摸一样的。

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

AVL树的验证

验证有序

我们首先需要写一个中序遍历来看看插入的数据是否符合预期。

void InOrder()
{_InOrder(_root);cout << endl;
}void _InOrder(Node* root)
{if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);
}

我们来跑个测试用例。

void test_AVLTree1()
{AVLTree<int, int> avlT1;AVLTree<int, int> avlT2;int a1[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };int a2[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };for (auto e : a1){avlT1.Insert({ e, e });}for (auto e : a2){avlT2.Insert({ e, e });}avlT1.InOrder();avlT2.InOrder();}

可以看到结果是没问题的。

验证平衡

int Height()
{return _Height(_root);
}int _Height(Node* root)
{if (root == nullptr)return 0;int LeftHeight = _Height(root->_left);int RightHeight = _Height(root->_right);return (LeftHeight > RightHeight ? LeftHeight : RightHeight) + 1;
}bool IsBalanceTree()
{return _IsBalanceTree(_root);
}bool _IsBalanceTree(Node* root)
{// 空树也是AVL树if (root == nullptr)return true;// 计算pRoot结点的平衡因子:即Root左右子树的高度差int LeftHeight = _Height(root->_left);int RightHeight = _Height(root->_right);int diff = RightHeight - LeftHeight;// 如果计算出的平衡因子与Root的平衡因子不相等,或者// pRoot平衡因子的绝对值超过1,则一定不是AVL树if (abs(diff) >= 2){cout << root->_kv.first << "高度异常" << endl;return false;}if (root->_bf != diff){cout << root->_kv.first << "平衡因子异常" << endl;return false;}// pRoot的左和右如果都是AVL树,则该树一定是AVL树return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);

我们用大量数据来测试下。

void test_AVLTree2()
{const int N = 1000000;vector<int> v;v.reserve(N);srand((unsigned int)time(0));for (size_t i = 0; i < N; i++){v.push_back(rand() + i);}AVLTree<int, int> t;for (auto e : v){t.Insert(make_pair(e, e));}if (t.IsBalanceTree())cout << "是AVL树" << endl;elsecout << "不是AVL树" << endl;cout << "Height:" << t.Height() << endl;cout << "Size:" << t.Size() << endl;}

完整代码

#include<iostream>
#include<assert.h>
using namespace std;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: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 (kv.first > cur->_kv.first)cur = cur->_right;else if (kv.first < cur->_kv.first)cur = cur->_left;elsereturn false;}cur = new Node(kv);//将父节点与新节点链接//判断新节点插入到parent的左边还是右边if (kv.first > parent->_kv.first) //新节点插入到parent的右边parent->_right = cur;elseparent->_left = cur;//更改新节点的父亲指针cur->_parent = parent;//更新平衡因子while (parent){//插入节点后除了对父节点造成影响还可能对祖宗节点造成影响//随着循环进行,cur不一定为新节点//更新父节点的平衡因子if (cur == parent->_left)parent->_bf--;elseparent->_bf++;//检查更新后父亲的平衡因子//_bf为0,说明树还是AVL树,退出循环if (parent->_bf == 0)break;//_bf == 1/-1,说明需要继续向上更新平衡因子else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}//_bf == 2/-2,说明AVL树失衡,需要进行旋转操作else if (parent->_bf == 2 || parent->_bf == -2){//插入后AVl树失衡,需要进行平衡调整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);elseassert(false);break;}elseassert(false);}return true;}void RotateR(Node* parent){//subL为parent的左孩子节点Node* subL = parent->_left;//subLR为subL的右子节点Node* subLR = subL->_right;// 将parent与subLR节点进行链接parent->_left = subLR;//在SubLR的情况下更改,让其指向正确的父亲if (subLR)subLR->_parent = parent;//提前记录祖父节点Node* pParent = parent->_parent;//链接subL与parentsubL->_right = parent;parent->_parent = subL;//根据parent是否是根节点进行不同处理if (parent == _root){_root = subL;subL->_parent = nullptr;}else {//将pParent和subL链接//但得先判断parent是pParent的左节点还是右节点if (pParent->_left == parent)pParent->_left = subL;elsepParent->_right = subL;//修改subL的parent指针,让其指向正确的父亲subL->_parent = pParent;}//更新平衡因子subL->_bf = parent->_bf = 0;}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* pParent = parent->_parent;subR->_left = parent;parent->_parent = subR;if (parent == _root){_root = subR;subR->_parent = nullptr;}else{if (pParent->_left == parent)pParent->_left = subR;elsepParent->_right = subR;subR->_parent = pParent;}subR->_bf = parent->_bf = 0;}void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;//记录subLR的bf,根据其取值更新左右双旋后各个节点的bfint bf = subLR->_bf;	RotateL(subL);RotateR(parent);subLR->_bf = 0;if (bf == -1){subL->_bf = 0;parent->_bf = 1;}else if (bf == 1){subL->_bf = -1;parent->_bf = 0;}else if (bf == 0){subL->_bf = 0;parent->_bf = 0;}elseassert(false);}void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);subRL->_bf = 0;if (bf == -1){subR->_bf = 1;parent->_bf = 0;}else if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == 0){subR->_bf = 0;parent->_bf = 0;}elseassert(false);}void InOrder(){_InOrder(_root);cout << endl;}int Height(){return _Height(_root);}int Size(){return _Size(_root);}bool IsBalanceTree(){return _IsBalanceTree(_root);}Node* Find(const K& key){Node* cur = _root;while (cur){if (key > cur->_kv.first)cur = cur->_right;else if (key > cur->_kv.first)cur = cur->_left;elsereturn cur;}return nullptr;}private:void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}int _Height(Node* root){if (root == nullptr)return 0;int LeftHeight = _Height(root->_left);int RightHeight = _Height(root->_right);return (LeftHeight > RightHeight ? LeftHeight : RightHeight) + 1;}int _Size(Node* root){if (root == nullptr)return 0;return _Size(root->_left) + _Size(root->_right) + 1;}bool _IsBalanceTree(Node* root){// 空树也是AVL树if (root == nullptr)return true;// 计算pRoot结点的平衡因子:即Root左右子树的高度差int LeftHeight = _Height(root->_left);int RightHeight = _Height(root->_right);int diff = RightHeight - LeftHeight;// 如果计算出的平衡因子与Root的平衡因子不相等,或者// pRoot平衡因子的绝对值超过1,则一定不是AVL树if (abs(diff) >= 2){cout << root->_kv.first << "高度异常" << endl;return false;}if (root->_bf != diff){cout << root->_kv.first << "平衡因子异常" << endl;return false;}// pRoot的左和右如果都是AVL树,则该树一定是AVL树return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);}private:Node* _root = nullptr;
};

拜拜,下期再见😏

摸鱼ing😴✨🎞

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/464477.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx线程模型

Nginx的线程模型具有其独特的设计特点&#xff0c;主要基于多进程和异步非阻塞的处理机制。以下是对Nginx线程模型的详细解析&#xff1a; 一、多进程模型 Nginx采用的是多进程模型&#xff0c;而非多线程模型。在这种模型中&#xff0c;Nginx会启动一个master进程和多个work…

【HTML】——VSCode 基本使用入门和常见操作

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 零&#xff1a;HTML开发工具VSCode的使用 1&#xff1a;创建项目 2&#xff1a;创建格式模板&#x…

【C/C++】【三种方法】模拟实现strlen

学习目标&#xff1a; 使用代码模拟实现strlen。 逻辑&#xff1a; strlen 需要输入一个字符串数组类型的变量&#xff0c;并且返回一个整型类型的数据。strlen 需要计算字符串数组有多少个元素。 代码1&#xff1a;使用计数器 #define _CRT_SECURE_NO_WARNINGS 1 #include&…

【双指针】【数之和】 LeetCode 633.平方数之和

算法思想&#xff1a; 双指针枚举i,j&#xff1b;类似三数之和 class Solution { public:bool judgeSquareSum(int c) {long long sum0;vector<int> dp;dp.push_back(0);long long start1;while(sum < c){sum start *start;if(sum>c) break;else dp.push_back(…

HarmonyOS Next星河版笔记--界面开发(3)

属性 1.1.设计资源-svg图标 需求&#xff1a;界面中展示图标→可以使用的svg图标(任意放大缩小不失真、可以改变颜色) 使用方式&#xff1a; ①设计师提供&#xff1a;基于项目的图标&#xff0c;拷贝到项目目录使用 Image($r(app.media.ic_dianpu)) .width(40) fillColor…

解决方案 | 部署更快,自动化程度高!TOSUN同星线控底盘解决方案

Tosun——线控底盘解决方案 在汽车智能化和电动化进程中&#xff0c;智能线控底盘相关的核心技术和产品成为了新能源汽车及智能驾驶产业的重点发展方向。同星智能作为行业先行者&#xff0c;精研汽车电子行业整体解决方案&#xff0c;提供基于TSMaster的底盘HIL仿真测试解决方…

分布式光伏管理办法

随着分布式光伏项目的不断增加&#xff0c;传统的管理方式已经难以满足高效、精准的管理需求。光伏业务管理系统作为一种集信息化、智能化于一体的管理工具&#xff0c;正在逐步成为分布式光伏项目管理的重要支撑。 光伏业务管理系统通过数字化手段实现对光伏业务全流程的精细化…

细腻的链接:C++ list 之美的解读

细腻的链接&#xff1a;C list 之美的解读 前言&#xff1a; 小编在前几日刚写过关于vector容器的内容&#xff0c;现在小编list容器也学了一大部分了&#xff0c;小编先提前说一下学这部分的感悟&#xff0c;这个部分是我学C以来第一次感到有难度的地方&#xff0c;特别是在…

文件操作案例

文件操作&#xff08;帮助小学生控诉妈妈&#xff09;:###无任何不良指导###

基于 RNN 的语言模型

基于 RNN 的语言模型 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一类网络连接中包含环路的 神经网络的总称。 给定一个序列&#xff0c;RNN 的环路用于将历史状态叠加到当前状态上。沿着时间维度&#xff0c;历史状态被循环累积&#xff0c;并作为…

嵌入式硬件工程师的职业发展规划

嵌入式硬件工程师可以按照以下阶段进行职业发展规划&#xff1a; 1. **初级阶段&#xff08;1-3 年&#xff09; ** - **技术学习与积累**&#xff1a; **电路基础强化**&#xff1a; 深入学习模拟电路和数字电路知识&#xff0c;能够熟练分析和设计基本的电路&#xff0c;…

C#:强大而优雅的编程语言

在当今的软件开发领域&#xff0c;C#作为一种广泛应用的编程语言&#xff0c;以其强大的功能、优雅的语法和丰富的生态系统&#xff0c;受到了众多开发者的喜爱。本文将深入探讨 C#的各个方面&#xff0c;展示它的魅力和优势。 一、C#的历史与发展 C#是由微软公司开发的一种面…

时间序列预测(十八)——实现配置管理和扩展命令行参数解析器

如图&#xff0c;这是一个main,py文件&#xff0c;在此代码中&#xff0c;最开始定义了许多模型参数&#xff0c;为了使项目更加灵活和可扩展&#xff0c;便于根据不同的需求调整参数和配置&#xff0c;可以根据实际需要扩展参数和配置项。 下面是如何实现配置管理和扩展命令行…

影刀RPA实战:嵌入python,如虎添翼

1. 影刀RPA与Python的关系 影刀RPA与Python的关系可以从以下几个方面来理解&#xff1a; 技术互补&#xff1a;影刀RPA是一种自动化工具&#xff0c;它允许用户通过图形化界面创建自动化流程&#xff0c;而Python是一种编程语言&#xff0c;常用于编写自动化脚本。影刀RPA可以…

GR2——在大规模视频数据集上预训练且机器人数据上微调,随后预测动作轨迹和视频(含GR1详解)

前言 上个月的24年10.9日&#xff0c;我在朋友圈看到字节发了个机器人大模型GR2&#xff0c;立马去看了下其论文(当然了&#xff0c;本质是个技术报告) 那天之后&#xff0c;我就一直想解读这个GR2来着 然&#xff0c;意外来了&#xff0c;如此文《OmniH2O——通用灵巧且可全…

Hive自定义函数—剔除周日周六(小时级别)

&#x1f431;背景&#x1f34e; Hello&#xff0c;小伙伴们&#xff0c;许久不见&#xff0c;最近遇到一个需求场景&#xff0c;关于物流时差的计算&#xff0c;要求算出差值是小时&#xff0c;且要剔除周日周六&#xff0c;网上很多文章&#xff0c;最好的也就是按照天剔除周…

C++中的继承——第二篇

一、继承与友元 友元关系不能够继承&#xff08;就像父亲的朋友不一定是自己的朋友&#xff09; 具体实现起来就是父类的友元可以访问父类的成员&#xff0c;但是不可以访问子类的成员 二、继承与静态成员 子类的静态成员变量本质上与父类的是同一份&#xff0c;存储在静态…

02多线程基础知识

目录 1. 线程与进程 进程&#xff08;Process&#xff09; 线程&#xff08;Thread&#xff09; 2. 并发和并行 并发&#xff08;Concurrency&#xff09; 并行&#xff08;Parallelism&#xff09; 3. CPU 调度 定义 类型 调度算法 上下文切换 4.线程间的状态流转…

基于SpringBoot+Gpt个人健康管家管理系统【提供源码+答辩PPT+参考文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

Kotlin by lazy和lateinit的使用及区别

在 Kotlin 中&#xff0c;lateinit 和 by lazy 都可以用来延迟初始化变量&#xff0c;但它们有不同的适用场景和使用方式。下面详细介绍它们的用法和区别。 1.lateinit lateinit 关键字用于延迟初始化 可变属性 (var)&#xff0c;主要用于那些在声明时不能立即初始化&#xf…