AVL树 ---(C++)
本篇讲全面的讲解 AVL 树的插入,旋转以及验证 AVL 树的性能(本篇未实现删除代码)。至于为什么会有 AVL 树,这是因为简单的二叉搜索树并不能直接的保证搜索的效率,因为当我们在二叉搜索树中插入一段有序的序列的时候,二叉搜索树就会退化为单枝树,这个时候进行搜索的时候,时间复杂度就变为了 O(n^2),如下:
但是通过 AVL 树的旋转就可以很好的解决这个问题,使树近似等于完全二叉树或者满二叉树。
AVL 树代码
先给出代码,接着在下文中给出解释:
#pragma once #include <iostream> #include <assert.h>using namespace std;template <class K, class V> struct AVLTreeNode {AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;pair<K, V> _kv;int _balanceFactor;AVLTreeNode(const pair<K, V>& kv): _left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _balanceFactor(0){} };template <class K, class V> class AVLTree { public:typedef AVLTreeNode<K, V> Node;Node* find(const K& key) {Node* cur = _root;while (cur) {if (cur->_kv.first < key)cur = cur->_right;else if (cur->_kv.first > key)cur = cur->_left;elsereturn cur;}return nullptr;}// 插入删除查找遍历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;elsereturn false;}// cur == nullptrcur = new Node(kv);//if (parent->_left == cur)// parent->_left = cur;//else// parent->_right = cur;if (parent->_kv.first > kv.first)parent->_left = cur;elseparent->_right = cur;cur->_parent = parent;// 需要更新平衡因子// 如果是在父亲的左边,父亲的平衡因子减一、右边加一if (parent->_left == cur)parent->_balanceFactor--;elseparent->_balanceFactor++;// 查看爷爷结点是否需要更新while (parent) {if (parent->_balanceFactor == 0) {break;}else if (parent->_balanceFactor == 1 || parent->_balanceFactor == -1) {if (parent == _root)break;// 现在的parent就不可能等于nullparent = parent->_parent;cur = cur->_parent;if (parent->_left == cur)parent->_balanceFactor--;elseparent->_balanceFactor++;}else if(parent->_balanceFactor == 2 || parent->_balanceFactor == -2) {if (parent->_balanceFactor == 2 && cur->_balanceFactor == 1)RotateLeft(parent);else if (parent->_balanceFactor == -2 && cur->_balanceFactor == -1)RotateRight(parent);else if (parent->_balanceFactor == -2 && cur->_balanceFactor == 1)RotateLeftRight(parent);else if (parent->_balanceFactor == 2 && cur->_balanceFactor == -1)RotateRightLeft(parent);elseassert(false);break;}else {assert(false);}}return true;}void RotateRight(Node* parent) {Node* subL = parent->_left;Node* subLR = subL->_right;// 将左孩子的右节点链接到原父亲结点if (subLR) subLR->_parent = parent;parent->_left = subLR;Node* ppNode = parent->_parent;// 将左孩子变为原父亲结点的父亲subL->_right = parent;parent->_parent = subL;// 将爷爷结点重新链接if (ppNode == nullptr) {_root = subL;_root->_parent = nullptr;}else {if (ppNode->_left == parent)ppNode->_left = subL;elseppNode->_right = subL;subL->_parent = ppNode;}subL->_balanceFactor = parent->_balanceFactor = 0;}void RotateLeft(Node* parent) {Node* subR = parent->_right;Node* subRL = subR->_left;Node* ppNode = parent->_parent;parent->_right = subRL;if (subRL) subRL->_parent = parent;subR->_left = parent;parent->_parent = subR;if (ppNode == nullptr) {_root = subR;_root->_parent = nullptr;}else {if (ppNode->_left == parent)ppNode->_left = subR;elseppNode->_right = subR;subR->_parent = ppNode;}subR->_balanceFactor = parent->_balanceFactor = 0;}void RotateRightLeft(Node* parent) {Node* subR = parent->_right;Node* subRL = subR->_left;int balanceFactor = subRL->_balanceFactor;RotateRight(subR);RotateLeft(parent);// 更新平衡因子subRL->_balanceFactor = 0;if (balanceFactor == -1) {parent->_balanceFactor = 0;subR->_balanceFactor = 1;}else if (balanceFactor == 1) {parent->_balanceFactor = -1;subR->_balanceFactor = 0;}else if (balanceFactor == 0) {parent->_balanceFactor = 0;subR->_balanceFactor = 0;}else {assert(false);}}void RotateLeftRight(Node* parent) {Node* subL = parent->_left;Node* subLR = subL->_right;int balanceFactor = subLR->_balanceFactor;// 先左旋后右旋RotateLeft(subL);RotateRight(parent);subLR->_balanceFactor = 0;if (balanceFactor == -1) {subL->_balanceFactor = 0;parent->_balanceFactor = 1;}else if (balanceFactor == 1) {parent->_balanceFactor = 0;subL->_balanceFactor = -1;}else if (balanceFactor == 0) {parent->_balanceFactor = 0;subL->_balanceFactor = 0;}else {assert(false);}}void InOrder() {_InOrder(_root);cout << endl;}int height() {int h = _height(_root);return h;}int size() {int s = _size(_root);return s;}bool IsBalance() {return _IsBalance(_root);}private:bool _IsBalance(Node* root) {if (root == nullptr)return true;int leftHeight = _height(root->_left);int rightHeight = _height(root->_right);if (abs(leftHeight - rightHeight) >= 2)return false;if (abs(root->_balanceFactor) >= 2)return false;return _IsBalance(root->_left) && _IsBalance(root->_right);}int _height(Node* root) {if (root == nullptr)return 0;int left = _height(root->_left);int right = _height(root->_right);int height = max(left, right);return height + 1;}int _size(Node* root) {if (root == nullptr)return 0;return _size(root->_left) + _size(root->_right) + 1;}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; };
AVL 树的概念于抽象数据结构
一颗 AVL 树是空树或者是具有以下性质的二叉搜索树:
1. 它的左右子树都是 AVL 树
2. 左右子树的高度之差(平衡因子)的绝对值不超过 1
左右子树的高度差不超过 1,可以降低树的高度,减少平均搜索长度。如下:
关于 AVL 树的抽象数据结构,我们首先需要抽象出 AVL 树节点的数据结构,在 AVL 树中,我们存储的关键数据为键值对 pair,AVL 树节点中的平衡因子。然后需要一个指向左子树的指针,指向右子树的指针同时还需要一个指向父节点的指针,可以让我们便于更新每个节点的平衡因子。如下:
template <class K, class V> struct AVLTreeNode {AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;pair<K, V> _kv;int _balanceFactor;AVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _balanceFactor(0){} };
AVL 树的插入
关于 AVL 树而言,只是在二叉搜索树的基础上引入了平衡因子,所以 AVL 树也可以看出二叉搜索树(左右高度差不大于1的二叉搜索树),所以对于 AVL 树的插入,可以分为以下两步:
1. 按照二叉搜索树的方式插入新节点。
2. 调整节点的平衡因子。
所以我们插入节点,只需要找到应该插入的位置,然后插入即可,寻找插入位置按照:键值小于当前节点,向左子树搜索,键值大于当前节点,向右子树搜索的原则,直到找到空节点为止,就是应该插入的位置。寻找的时候,还需要记录下每一次搜索的父节点,便于链接指针,如下:
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;elsereturn false;}// cur == nullptrcur = new Node(kv);// 链接孩子节点和父节点if (parent->_kv.first > kv.first)parent->_left = cur;elseparent->_right = cur;cur->_parent = parent;// 需要更新平衡因子...return true; }
插入成功,则返回 true,插入失败(树中已经存在键值)则返回 false。
以上只是完成了插入,插入元素之后,我们还需要更新节点的平衡因子,更新平衡因子按照以下原则进行更新:
1. 插入元素位置位于父节点的右边,父节点的平衡因子 +1;
2. 插入元素位置位于父节点的左边,父节点的平衡因子 -1。
3. 更新完父节点的平衡因子之后,父节点的平衡因子的取值可能为 0、正负1、正负2。
5. 父节点的平衡因子更新完之后为0,不会影响父节点的父节点的平衡,所以不用在往上更新。
6. 父节点的平衡因子跟新完之后为正负1,说明原来父节点的平衡因子为0,这时还会影响父节点的父节点的平衡因子,所以需要继续向上更新。当某个节点的平衡原则为正负二的时候,我们就需要通过选择使树平衡。
如下:
// 需要更新平衡因子 // 如果是在父亲的左边,父亲的平衡因子减一、右边加一 if (parent->_left == cur)parent->_balanceFactor--; elseparent->_balanceFactor++; // 查看爷爷结点是否需要更新while (parent) {if (parent->_balanceFactor == 0) {break;}else if (parent->_balanceFactor == 1 || parent->_balanceFactor == -1) {if (parent == _root)break;// 现在的parent就不可能等于nullparent = parent->_parent;cur = cur->_parent;if (parent->_left == cur)parent->_balanceFactor--;elseparent->_balanceFactor++;}else if(parent->_balanceFactor == 2 || parent->_balanceFactor == -2) {if (parent->_balanceFactor == 2 && cur->_balanceFactor == 1)RotateLeft(parent);else if (parent->_balanceFactor == -2 && cur->_balanceFactor == -1)RotateRight(parent);else if (parent->_balanceFactor == -2 && cur->_balanceFactor == 1)RotateLeftRight(parent);else if (parent->_balanceFactor == 2 && cur->_balanceFactor == -1)RotateRightLeft(parent);elseassert(false);break;}else {assert(false);} }
对于如上的代码中,其中最难的一步就是旋转,关于旋转一共会出现四种情况:左单旋、右单旋、左右双旋、右左双旋。
AVL 树的旋转
我们首先介绍右单旋,当新节点插入导较高左子树的左侧就会出现右单旋,关于右单旋出现的情况如下:
当出现如上所示的情况时(父亲节点的平衡因子等于-2,左孩子节点的平衡因子为-1时),我们就需要进行右旋,也就是将左孩子作为父节点,父节点作为右孩子,在将左孩子的右节点链接到原父节点上。其中还有需要注意的点:右旋时的父节点不一定是根节点,所以我们在旋转的时候,还需要记录下父节点的父节点,最后将其链接到一起。
void RotateRight(Node* parent) {Node* subL = parent->_left;Node* subLR = subL->_right;// 将左孩子的右节点链接到原父亲结点if (subLR) subLR->_parent = parent;parent->_left = subLR;Node* ppNode = parent->_parent;// 将左孩子变为原父亲结点的父亲subL->_right = parent;parent->_parent = subL;// 将爷爷结点重新链接if (ppNode == nullptr) {_root = subL;_root->_parent = nullptr;}else {if (ppNode->_left == parent)ppNode->_left = subL;elseppNode->_right = subL;subL->_parent = ppNode;}subL->_balanceFactor = parent->_balanceFactor = 0; }
记得最后将节点的平衡因子设置为0。
接着我们介绍左单旋:当新节点插入到较高右子树的右侧,关于这种情况如下:
关于左单旋,其思想和右单旋基本一致,不过是将右单旋的给镜像了过来。所以当父节点的平衡因子为2,右节点的平衡因子为1的时候,我们就需要对树进行左单旋。也就是让右孩子的左节点作为父节点的右孩子,左节点作为父节点,原父节点作为左孩子的左节点。注意原父节点的父节点是否为 nullptr,最后需要更新节点的平衡因子。如下:
void RotateLeft(Node* parent) {Node* subR = parent->_right;Node* subRL = subR->_left;Node* ppNode = parent->_parent;parent->_right = subRL;if (subRL) subRL->_parent = parent;subR->_left = parent;parent->_parent = subR;if (ppNode == nullptr) {_root = subR;_root->_parent = nullptr;}else {if (ppNode->_left == parent)ppNode->_left = subR;elseppNode->_right = subR;subR->_parent = ppNode;}subR->_balanceFactor = parent->_balanceFactor = 0; }
第三种情况,左右双旋。左右双旋就是分别需要左旋一次,然后右旋一次,接着更新我们的平衡因子,如下:
如上图所示,当左孩子节点的平衡因子为1,父节点的平衡因子为-2的时候,我们就需要进行左右双旋,当我们旋转之后,当前父节点的平衡因子一定为0,但原父节点和左孩子节点的平衡因子一共有三种情况,分别是0 0,1 0,0 -1。当 h = 0 的时候,插入的节点就是以上的60节点,旋转之后所有节点(一共就3个节点)都是为0,当节点插入到60的左边,那么30的平衡因子为0(如图),当节点插入到60的右边,90的平衡因子则为0。
因为在单独调用左单选,右单旋之后,会将所有节点的平衡因子都置为0,所以我们需要进行特殊处理。如下:
void RotateLeftRight(Node* parent) {Node* subL = parent->_left;Node* subLR = subL->_right;int balanceFactor = subLR->_balanceFactor;// 先左旋后右旋RotateLeft(subL);RotateRight(parent);subLR->_balanceFactor = 0;if (balanceFactor == -1) {subL->_balanceFactor = 0;parent->_balanceFactor = 1;}else if (balanceFactor == 1) {parent->_balanceFactor = 0;subL->_balanceFactor = -1;}else if (balanceFactor == 0) {parent->_balanceFactor = 0;subL->_balanceFactor = 0;}else {assert(false);} }
最后一种情况:右左双旋。也就是先右旋然后在左旋,也就是和以上的情况是堆成的情况,如下:
对于需要右左旋转的情况为父节点为2,右孩子为1.关于转换的细节和以上的左右双旋的情况向对称,在这就不细讲了,代码如下:
void RotateRightLeft(Node* parent) {Node* subR = parent->_right;Node* subRL = subR->_left;int balanceFactor = subRL->_balanceFactor;RotateRight(subR);RotateLeft(parent);// 更新平衡因子subRL->_balanceFactor = 0;if (balanceFactor == -1) {parent->_balanceFactor = 0;subR->_balanceFactor = 1;}else if (balanceFactor == 1) {parent->_balanceFactor = -1;subR->_balanceFactor = 0;}else if (balanceFactor == 0) {parent->_balanceFactor = 0;subR->_balanceFactor = 0;}else {assert(false);} }
AVL 树的验证 + 测试
接下来我们将对我们是新的 AVL 树进行验证,也就是看我们写出的代码是否符合 AVL 树的特性,其中主要包括特性测试和压力测试。在进行测试之前,我们需要先写出一些辅助函数,如下:
template <class K, class V> class AVLTree { public:typedef AVLTreeNode<K, V> Node;void InOrder() {_InOrder(_root);cout << endl;}int height() {int h = _height(_root);return h;}int size() {int s = _size(_root);return s;}bool IsBalance() {return _IsBalance(_root);}private:bool _IsBalance(Node* root) {if (root == nullptr)return true;int leftHeight = _height(root->_left);int rightHeight = _height(root->_right);if (abs(leftHeight - rightHeight) >= 2)return false;if (abs(root->_balanceFactor) >= 2)return false;return _IsBalance(root->_left) && _IsBalance(root->_right);}int _height(Node* root) {if (root == nullptr)return 0;int left = _height(root->_left);int right = _height(root->_right);int height = max(left, right);return height + 1;}int _size(Node* root) {if (root == nullptr)return 0;return _size(root->_left) + _size(root->_right) + 1;}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 TestAVL01() {int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };// {16, 3, 7, 11, 9, 26, 18, 14, 15}AVLTree<int, int> avtree;for (auto e : a) {if (e == 4) {int i = 0;}avtree.insert(make_pair(e, e));}avtree.InOrder();cout << avtree.height() << endl;cout << avtree.size() << endl;cout << avtree.IsBalance() << endl; }void TestAVL02() {const int N = 1000000;vector<int> v;v.reserve(N);srand(time(0));for (int i = 0; i < N; i++) {v.push_back(rand() + 1);}size_t begin1 = clock();AVLTree<int,int> tree;for (auto e : v)tree.insert({e, e});size_t end1 = clock();cout << "insert" << end1 - begin1 << endl;cout << "Height:" << tree.height() << endl;cout << "Size:" << tree.size() << endl;size_t begin2 = clock();for (auto e : v)tree.find(e);size_t end2 = clock();cout << "find:" << end2 - begin2 << endl;cout << tree.IsBalance() << endl; }
相关文章:
AVL树 ---(C++)
本篇讲全面的讲解 AVL 树的插入,旋转以及验证 AVL 树的性能(本篇未实现删除代码)。至于为什么会有 AVL 树,这是因为简单的二叉搜索树并不能直接的保证搜索的效率,因为当我们在二叉搜索树中插入一段有序的序列的时候&am…...
基于spring boot+MySQL 小区物业管理系统-计算机毕设 附源码37236
spring boot 小区物业管理系统 摘 要 在网络信息的时代,众多的软件被开发出来,给用户带来了很大的选择余地,而且人们越来越追求更个性的需求。在这种时代背景下,小区物业只能以客户为导向,以产品的持续创新作为小区物…...
Linux/Ubuntu/Debian常用服务管理命令
Linux/Ubuntu/Debian常用服务管理命令 在 Linux 系统中,服务管理是系统管理员日常维护工作的重要组成部分。通过一些常用的命令,我们可以查看服务状态、启动或停止服务、重启服务等。掌握这些命令,可以让系统管理工作更加高效和便捷。 1. s…...
Maven的三种项目打包方式——pom,jar,war的区别
1、pom:用在父级工程或聚合工程中,用来做jar包的版本控制,必须指明这个聚合工程的打包方式为pom。 聚合工程只是用来帮助其他模块构建的工具,本身并没有实质的内容。具体每个工程代码的编写还是在生成的工程中去写。 对于在父工程…...
[手游] 三色绘恋S Mobile Link
语音合成TTS: 文字转成语音的工具 WPS免登录一键修改器: 去除烦人的登录且能正常使用 故事简介: 深秋的雨季即将到来,正值那个为人所熟知的故事发生的前一年—— 地点:湖北省的重点高中,武汉师贰高校。 新学年开始,各…...
nss刷题(4)
1、[SWPUCTF 2021 新生赛]easyrce <?php error_reporting(0); highlight_file(__FILE__); if(isset($_GET[url])) { eval($_GET[url]); } ?> if(isset($_GET[url])) isset函数用来检测url变量是否存在;$_GET函数获取变量数据 eval($_GET[url]); eval函数用…...
iOS调整collectionViewCell顺序
效果图 原理 就是设置collectionView调整顺序的代理方法,这里要注意一点 调整过代理方法之后,一定要修改数据源,否则导致错乱。 还有就是在collectionView上面添加一个长按手势,在长按手势的不同阶段,调用collectionV…...
【回调函数】
1.回调函数是什么? 回调函数就是⼀个通过函数指针调用的函数。 如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被用来调用其所指向的函数 时,被调用的函数就是回调函数。回调函数不是由该函数的实现方…...
找树左下角的值-力扣
本题个人认为不能叫做 找树左下角的值,左下角再怎么说也应当在树的左子树上,本题要求的节点是树最底层最左边的值。 首先想到的解法是对二叉树进行层序遍历,并记录本层第一个节点的值,当层序遍历结束时,此时记录的值即…...
【AI应用探讨】— Gemma2模型应用场景
目录 1. 金融风险管理 2. 营销策略优化 3. 医疗保健领域 4. 供应链管理 5. 人力资源管理 6. 自然语言处理(NLP) 7. 图像识别 8. 音频信号处理 9. 总结 1. 金融风险管理 场景描述:Gemma 2模型在金融领域可用于预测金融市场的波动性和…...
树二叉树
树 树是 n(n≥0)个结点的有限集。当 n 0时,称为空树。在任意一颗非空树中应满足: (1)有且仅有一个特定的称为根的结点。 (2)当 n > 1时,其余结点可分为 m&…...
无源晶振振荡电路失效问题分析与解决策略
无源晶振(晶体谐振器)在电子设备中扮演着至关重要的角色,为数字电路提供稳定的时钟信号。然而,振荡电路一旦失效,可能会导致整个系统运行不正常。晶发电子将从三个主要方面分析无源晶振振荡电路失效的问题,…...
LIMS系统在汽车第三方检测实验室的应用
随着汽车行业的快速发展,汽车第三方检测实验室的工作量不断增加,对实验室的管理效率和数据准确性提出了更高的要求。LIMS系统的引入可以实现实验室的全面数字化管理,提高工作效率,降低运营成本,并提升数据质量与决策支…...
positivessl泛域名https证书
PositiveSSL,作为Sectigo旗下的子品牌,一直以来颁发的https数字证书产品性价比较高,适合大多数个人网站和中小型企业。其中,DV基础型的泛域名https证书以申请简单、颁发速度快、价格低受到众多用户的欢迎。今天就随SSl盾小编了解P…...
MySQL bin-log日志恢复数据
目录 一、开启二进制日志 二、检查二进制日志是否开启 三、使用二进制日志备份和恢复 使用二进制日志备份恢复前先创建备份: 应用二进制日志: 扩展用法: 四、常见命令和操作 五. 使用 mysqlbinlog 工具查看二进制日志 1. 查看二进制…...
Linux网络命令——netstat
netstat是Linux系统中非常有用的网络工具,被称为是网络监控中的军工刀,足见其地位。 传统上,它用于问题确定而不是性能测量,但是也可用于查看网络上的流量,以确定性能问题是否由于网络阻塞引起。 netstat用于显示与I…...
手机怎么压缩图片?通过三种压缩操作
手机怎么压缩图片?在智能手机日益普及的今天,拍照分享已成为日常生活的一部分。然而,高质量的照片往往占用较大的存储空间,且在网络上传输时速度较慢。那么,如何在手机上压缩图片呢?本文将介绍三种实用的手…...
分布式CAP、BASE理论务必了解一下
分布式系统理论是计算机科学中的一个重要分支,它关注如何设计和实现能够跨多个物理或逻辑位置运行的系统。在分布式系统中,CAP定理和BASE理论是两个非常著名的理论,它们分别描述了分布式系统设计中的一些基本约束和原则。 CAP定理 CAP定理&…...
spring最常用的注解
核心注解 Component 描述:将类标记为 Spring 组件,以便自动检测。用途:通常用于标注服务类或其他支持类。 Controller 描述:将类标记为 Spring MVC 控制器。用途:用于处理 Web 请求。 Service 描述:将类标记…...
Docker:认识镜像仓库及其命令
文章目录 Docker Registry什么是Docker Registry 镜像仓库工作机制使用流程实际使用方法仓库的拉取机制 常用的镜像仓库---DockerHub什么是DockerHub私有仓库 镜像仓库命令docker logindocker pulldocker pushdocker searchdocker logout Docker Registry 什么是Docker Regist…...
使用 Django 创建 App
文章目录 步骤 1:创建 Django 项目步骤 2:创建 App步骤 3:配置 App步骤 4:编写代码步骤 5:运行服务器 在 Django 中,App 是组织代码的基本单元,它可以包含模型、视图、模板等组件,帮…...
java定时任务 设置开始时间、结束时间;每周一、四、六执行;并且隔n周执行。最后计算所有执行时间
java定时任务 设置开始时间、结束时间;每周一、四、六执行;并且隔n周执行。最后计算所有执行时间) 定时任务需求程序设计依赖引入程序一、计算开始时间那周的周一时间二、根据executeTime和weekList.get(n),计算每个cron表达式。三、根据一和…...
linux的持续性学习
安装php 第一步:配置yum源 第二步:下载php。 yum install php php-gd php-fpm php-mysql -y 第三步:启动php。 systemctl start php-fpm 第四步:检查php是否启动 lsof -i :9000 计划任务 作用&am…...
MyBatis:概念简章
1. hello world 配置文件:mybatis-config.xml(核心配置文件,用于配置连接的数据库信息)(一般一个)XxxMapper.xml 该文件用于操作表(执行sql语句)(一张表一个)…...
有什么接码平台比较好用的
接码平台,也被称作短信接收平台或虚拟号码服务,主要是提供可以接收短信验证码的虚拟手机号码服务。这种服务通常被用于需要在网络平台上注册大量账号的情况,如营销推广、应用测试或是海淘购物时所需的手机号验证。下面将推荐几个较为好用的接…...
微服务之负载均衡器
1、负载均衡介绍 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上 进行执行。 根据负载均衡发生位置的不同, 一般分为服务端负载均衡和客户端负载均衡。 服务端负载均衡指的是发生在服务提供者一方ÿ…...
《时间管理九段》前四阶段学习笔记
文章目录 0.何谓时间管理九段0.1 第一段--把一件事做好0.2 第二段--把一天过好0.3 第三段--掌控两周内的固定日程0.4 第四段--掌控两周内的弹性时间0.5 第五段--科学管理3个月的项目事件0.6 第六段--实现一年的梦想0.7 第七段--明确一生的愿景0.8 第八段--正确补充和释放自身能…...
LLVM Cpu0 新后端5 静态重定位 动态重定位
想好好熟悉一下llvm开发一个新后端都要干什么,于是参考了老师的系列文章: LLVM 后端实践笔记 代码在这里(还没来得及准备,先用网盘暂存一下): 链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?…...
旅游卡是项目还是骗局?还是实实在在的旅游项目?
旅游卡是一个实实在在的旅游项目,而非骗局。以下是我对旅游卡项目的几点分析: 项目实质: 旅游卡项目是由国内外多条旅游线路整合而成的卡片,为旅游者提供方便、实惠的旅游方式。持有旅游卡,可以完全抵销跟团游线路中的…...
大模型+RAG,全面介绍!
1 、介绍 大型语言模型(LLMs)在处理特定领域或高度专业化的查询时存在局限性,如生成不正确信息或“幻觉”。缓解这些限制的一种有前途的方法是检索增强生成(RAG),RAG就像是一个外挂,将外部数据…...
免费个人网站怎么制作/免费刷网站百度关键词
def max_sub_str(line):lens = len(line)s = e = 0while s != lens-1:e = swhile e != lens-1:if line[s:e]...
网站在线优化/网站排名优化服务公司
1云里雾里的RAW到底是什么?最近小米手机3和诺基亚1520不约而同地在拍照方面增加了一项新功能——对RAW格式的支持。这让不少手机摄影达人惊喜不已,惊呼手机拍照的专业时代来临了。当然对于单反玩家来说RAW格式不算什么,但是在手机上应用确实具有里程碑式…...
贵阳专业做网站的公司/市场营销策划方案3000字
科目编号:8638 座位号 2017-2018学年度第二学期期末考试 薪酬制度与薪酬管理 试题 2018年 7 月 一、单选题(本大题共10小题,每小题3分,共计30分) (★请考生务必将答案填入到下面对应序号的答题框中★&…...
做p2p网站的公司/seo建设招商
//这张表存放的是所有单据模板的信息表 如果不知道单据模板的信息后可在数据库中查询PUB_BILLTEMPLET//这张表是打印模板的表改模板可以再此表修改pub_print_template//获取表头某个字段的值getBillCardPanel().getHeadItem("kitarea").getValueObject()//获取当前登…...
网站权重分散/百度号注册官网
1、接收参数是Date类型 接收参数前边加一个DateTimeFormat(pattern "yyyy-MM-dd") RequestMapping("/updateDate") public String updateDate(DateTimeFormat(pattern "yyyy-MM-dd") Date newDate) {return "redirect:list.do"; }…...
一级A视网站 一级做爰片/在百度上打广告找谁推广产品
当你遇到连接WordPress数据库链接错误时,可以有多个原因造成了这种错误。这时候 ,我们就要排查出是哪里出现的问题 ,我将在这篇文章中分享如何修复WordPress数据库连接错误时的故障排除和所有可能的原因。为什么数据库连接会发生错误通常 &am…...