【C++航海王:追尋羅杰的編程之路】關聯式容器的底層結構——AVL樹

目錄

1 -> 底層結構

2 -> AVL樹

2.1 -> AVL樹的概念

2.2 -> AVL樹節點的定義

2.3 -> AVL樹的插入

2.4 -> AVL樹的旋轉

2.5 -> AVL樹的驗證

2.6 -> AVL樹的性能


1 -> 底層結構

在上文中對對map/multimap/set/multiset進行了簡單的介紹,在其文檔介紹中發現,這幾個容器有個共同點是:其底層都是按照二叉搜索樹來實現的,但是二叉搜索樹有其自身的缺陷,假如往樹中
插入的元素有序或者接近有序,二叉搜索樹就會退化成單支樹,時間復雜度會退化成O(N),因此
map、set等關聯式容器的底層結構是對二叉樹進行了平衡處理,即采用平衡樹來實現。

2 -> AVL樹

2.1 -> AVL樹的概念

二叉搜索樹雖然可以縮短查找的效率,但如果數據有序或者接近有序的二叉搜索樹將退化成單支樹,查找元素相當于在順序表中搜索元素,效率低下。因此,兩位俄羅斯的數學家G.M.Adelson-Velskii和E.M.Landis在1962年發明了一種解決上述問題的方法:當向二叉搜索樹中插入新節點后,如果能保證每個節點的左右子樹的高度差的絕對值不超過1(需要對樹中的節點進行調整),即可降低樹的高度,從而減少平均搜索的長度。

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

  • 它的左右子樹都是AVL樹
  • 左右子樹高度之差(簡稱平衡因子)的絕對值不超過1(-1/0/1)

如果一棵二叉搜索樹是高度平衡的,它就是AVL樹。如果它有n個節點,其高度可保持在O(n),搜索時間復雜度O(n)。

2.2 -> AVL樹節點的定義

AVL樹節點的定義:

#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;template<class T>
struct AVLTreeNode
{AVLTreeNode(const T& data): _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr), _data(data), _bf(0){}AVLTreeNode<T>* _pLeft;   // 該節點的左孩子AVLTreeNode<T>* _pRight;  // 該節點的右孩子AVLTreeNode<T>* _pParent; // 該節點的雙親T _data;int _bf;				  // 該節點的平衡因子
};

2.3 -> AVL樹的插入

AVL樹就是在二叉搜索樹的基礎上引入了平衡因子,因此AVL樹也可以看成是二叉搜索樹。那么AVL樹的插入過程可以分為兩步:

  1. 按照二叉搜索樹的方式插入新節點。
  2. 調整節點的平衡因子。
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;template<class T>
struct AVLTreeNode
{AVLTreeNode(const T& data): _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr), _data(data), _bf(0){}AVLTreeNode<T>* _pLeft;   // 該節點的左孩子AVLTreeNode<T>* _pRight;  // 該節點的右孩子AVLTreeNode<T>* _pParent; // 該節點的雙親T _data;int _bf;				  // 該節點的平衡因子bool Insert(const T& data){// 1. 先按照二叉搜索樹的規則將節點插入到AVL樹中// 2. 新節點插入后,AVL樹的平衡性可能會遭到破壞,//	  此時就需要更新平衡因子,并檢測是否破壞了AVL樹的平衡性/*pCur插入后,pParent的平衡因子一定需要調整,在插入之前,pParent的平衡因子分為三種情況:-1,0, 1, 分以下兩種情況:1. 如果pCur插入到pParent的左側,只需給pParent的平衡因子-1即可2. 如果pCur插入到pParent的右側,只需給pParent的平衡因子+1即可此時:pParent的平衡因子可能有三種情況:0,正負1, 正負21. 如果pParent的平衡因子為0,說明插入之前pParent的平衡因子為正負1,插入后被調整成0,此時滿足AVL樹的性質,插入成功2. 如果pParent的平衡因子為正負1,說明插入前pParent的平衡因子一定為0,插入后被更新成正負1,此時以pParent為根的樹的高度增加,需要繼續向上更新3. 如果pParent的平衡因子為正負2,則pParent的平衡因子違反平衡樹的性質,需要對其進行旋轉處理*/while (pParent){// 更新雙親的平衡因子if (pCur == pParent->_pLeft)pParent->_bf--;elsepParent->_bf++;// 更新后檢測雙親的平衡因子if (0 == pParent->_bf){break;}else if (1 == pParent->_bf || -1 == pParent->_bf){// 插入前雙親的平衡因子是0,插入后雙親的平衡因為為1 或者 -1 ,說明以雙親為根的二叉樹// 的高度增加了一層,因此需要繼續向上調整pCur = pParent;pParent = pCur->_pParent;}else{// 雙親的平衡因子為正負2,違反了AVL樹的平衡性,需要對以pParent// 為根的樹進行旋轉處理if (2 == pParent->_bf){// ...}else{// ...}}}return true;}};

2.4 -> AVL樹的旋轉

如果在一棵原本是平衡的AVL樹中插入一個新節點,可能造成不平衡,此時必須調整樹的結構,使之平衡化。根據節點插入位置的不同,AVL樹的旋轉分為四種:

1. 新節點插入較高左子樹的左側——左左:右單旋

#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;template<class T>
struct AVLTreeNode
{AVLTreeNode(const T& data): _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr), _data(data), _bf(0){}AVLTreeNode<T>* _pLeft;   // 該節點的左孩子AVLTreeNode<T>* _pRight;  // 該節點的右孩子AVLTreeNode<T>* _pParent; // 該節點的雙親T _data;int _bf;				  // 該節點的平衡因子bool Insert(const T& data){// 1. 先按照二叉搜索樹的規則將節點插入到AVL樹中// 2. 新節點插入后,AVL樹的平衡性可能會遭到破壞,//	  此時就需要更新平衡因子,并檢測是否破壞了AVL樹的平衡性/*pCur插入后,pParent的平衡因子一定需要調整,在插入之前,pParent的平衡因子分為三種情況:-1,0, 1, 分以下兩種情況:1. 如果pCur插入到pParent的左側,只需給pParent的平衡因子-1即可2. 如果pCur插入到pParent的右側,只需給pParent的平衡因子+1即可此時:pParent的平衡因子可能有三種情況:0,正負1, 正負21. 如果pParent的平衡因子為0,說明插入之前pParent的平衡因子為正負1,插入后被調整成0,此時滿足AVL樹的性質,插入成功2. 如果pParent的平衡因子為正負1,說明插入前pParent的平衡因子一定為0,插入后被更新成正負1,此時以pParent為根的樹的高度增加,需要繼續向上更新3. 如果pParent的平衡因子為正負2,則pParent的平衡因子違反平衡樹的性質,需要對其進行旋轉處理*/while (pParent){// 更新雙親的平衡因子if (pCur == pParent->_pLeft)pParent->_bf--;elsepParent->_bf++;// 更新后檢測雙親的平衡因子if (0 == pParent->_bf){break;}else if (1 == pParent->_bf || -1 == pParent->_bf){// 插入前雙親的平衡因子是0,插入后雙親的平衡因為為1 或者 -1 ,說明以雙親為根的二叉樹// 的高度增加了一層,因此需要繼續向上調整pCur = pParent;pParent = pCur->_pParent;}else{// 雙親的平衡因子為正負2,違反了AVL樹的平衡性,需要對以pParent// 為根的樹進行旋轉處理if (2 == pParent->_bf){// ...}else{// ...}}}return true;}/*在插入前,AVL樹是平衡的,新節點插入到30的左子樹(注意:此處不是左孩子)中,30左子樹增加了一層,導致以60為根的二叉樹不平衡,要讓60平衡,只能將60左子樹的高度減少一層,右子樹增加一層,即將左子樹往上提,這樣60轉下來,因為60比30大,只能將其放在30的右子樹,而如果30有右子樹,右子樹根的值一定大于30,小于60,只能將其放在60的左子樹,旋轉完成后,更新節點的平衡因子即可。在旋轉過程中,有以下幾種情況需要考慮:1. 30節點的右孩子可能存在,也可能不存在2. 60可能是根節點,也可能是子樹如果是根節點,旋轉完成后,要更新根節點如果是子樹,可能是某個節點的左子樹,也可能是右子樹*/void _RotateR(PNode pParent){// pSubL: pParent的左孩子// pSubLR: pParent左孩子的右孩子PNode pSubL = pParent->_pLeft;PNode pSubLR = pSubL->_pRight;// 旋轉完成之后,30的右孩子作為雙親的左孩子pParent->_pLeft = pSubLR;// 如果30的左孩子的右孩子存在,更新親雙親if (pSubLR)pSubLR->_pParent = pParent;// 60 作為 30的右孩子pSubL->_pRight = pParent;// 因為60可能是棵子樹,因此在更新其雙親前必須先保存60的雙親PNode pPParent = pParent->_pParent;// 更新60的雙親pParent->_pParent = pSubL;// 更新30的雙親pSubL->_pParent = pPParent;// 如果60是根節點,根新指向根節點的指針if (NULL == pPParent){_pRoot = pSubL;pSubL->_pParent = NULL;}else{// 如果60是子樹,可能是其雙親的左子樹,也可能是右子樹if (pPParent->_pLeft == pParent)pPParent->_pLeft = pSubL;elsepPParent->_pRight = pSubL;}// 根據調整后的結構更新部分節點的平衡因子pParent->_bf = pSubL->_bf = 0;}
};

2. 新節點插入較高右子樹的右側——右右:左單旋

實現參考右單旋。

3. 新節點插入較高左子樹的右側——左右:先左單旋再右單旋

將雙旋變成單旋后再旋轉,即:先對30進行左單旋,然后再對90進行右單旋,旋轉完成后再考慮平衡因子的更新。

#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;template<class T>
struct AVLTreeNode
{AVLTreeNode(const T& data): _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr), _data(data), _bf(0){}AVLTreeNode<T>* _pLeft;   // 該節點的左孩子AVLTreeNode<T>* _pRight;  // 該節點的右孩子AVLTreeNode<T>* _pParent; // 該節點的雙親T _data;int _bf;				  // 該節點的平衡因子bool Insert(const T& data){// 1. 先按照二叉搜索樹的規則將節點插入到AVL樹中// 2. 新節點插入后,AVL樹的平衡性可能會遭到破壞,//	  此時就需要更新平衡因子,并檢測是否破壞了AVL樹的平衡性/*pCur插入后,pParent的平衡因子一定需要調整,在插入之前,pParent的平衡因子分為三種情況:-1,0, 1, 分以下兩種情況:1. 如果pCur插入到pParent的左側,只需給pParent的平衡因子-1即可2. 如果pCur插入到pParent的右側,只需給pParent的平衡因子+1即可此時:pParent的平衡因子可能有三種情況:0,正負1, 正負21. 如果pParent的平衡因子為0,說明插入之前pParent的平衡因子為正負1,插入后被調整成0,此時滿足AVL樹的性質,插入成功2. 如果pParent的平衡因子為正負1,說明插入前pParent的平衡因子一定為0,插入后被更新成正負1,此時以pParent為根的樹的高度增加,需要繼續向上更新3. 如果pParent的平衡因子為正負2,則pParent的平衡因子違反平衡樹的性質,需要對其進行旋轉處理*/while (pParent){// 更新雙親的平衡因子if (pCur == pParent->_pLeft)pParent->_bf--;elsepParent->_bf++;// 更新后檢測雙親的平衡因子if (0 == pParent->_bf){break;}else if (1 == pParent->_bf || -1 == pParent->_bf){// 插入前雙親的平衡因子是0,插入后雙親的平衡因為為1 或者 -1 ,說明以雙親為根的二叉樹// 的高度增加了一層,因此需要繼續向上調整pCur = pParent;pParent = pCur->_pParent;}else{// 雙親的平衡因子為正負2,違反了AVL樹的平衡性,需要對以pParent// 為根的樹進行旋轉處理if (2 == pParent->_bf){// ...}else{// ...}}}return true;}//1. 新節點插入較高左子樹的左側——左左:右單旋/*在插入前,AVL樹是平衡的,新節點插入到30的左子樹(注意:此處不是左孩子)中,30左子樹增加了一層,導致以60為根的二叉樹不平衡,要讓60平衡,只能將60左子樹的高度減少一層,右子樹增加一層,即將左子樹往上提,這樣60轉下來,因為60比30大,只能將其放在30的右子樹,而如果30有右子樹,右子樹根的值一定大于30,小于60,只能將其放在60的左子樹,旋轉完成后,更新節點的平衡因子即可。在旋轉過程中,有以下幾種情況需要考慮:1. 30節點的右孩子可能存在,也可能不存在2. 60可能是根節點,也可能是子樹如果是根節點,旋轉完成后,要更新根節點如果是子樹,可能是某個節點的左子樹,也可能是右子樹*/void _RotateR(PNode pParent){// pSubL: pParent的左孩子// pSubLR: pParent左孩子的右孩子PNode pSubL = pParent->_pLeft;PNode pSubLR = pSubL->_pRight;// 旋轉完成之后,30的右孩子作為雙親的左孩子pParent->_pLeft = pSubLR;// 如果30的左孩子的右孩子存在,更新親雙親if (pSubLR)pSubLR->_pParent = pParent;// 60 作為 30的右孩子pSubL->_pRight = pParent;// 因為60可能是棵子樹,因此在更新其雙親前必須先保存60的雙親PNode pPParent = pParent->_pParent;// 更新60的雙親pParent->_pParent = pSubL;// 更新30的雙親pSubL->_pParent = pPParent;// 如果60是根節點,根新指向根節點的指針if (NULL == pPParent){_pRoot = pSubL;pSubL->_pParent = NULL;}else{// 如果60是子樹,可能是其雙親的左子樹,也可能是右子樹if (pPParent->_pLeft == pParent)pPParent->_pLeft = pSubL;elsepPParent->_pRight = pSubL;}// 根據調整后的結構更新部分節點的平衡因子pParent->_bf = pSubL->_bf = 0;}//3. 新節點插入較高左子樹的右側——左右:先左單旋再右單旋// 旋轉之前,60的平衡因子可能是-1/0/1,旋轉完成之后,根據情況對其他節點的平衡因子進行調整void _RotateLR(PNode pParent){PNode pSubL = pParent->_pLeft;PNode pSubLR = pSubL->_pRight;// 旋轉之前,保存pSubLR的平衡因子,旋轉完成之后,需要根據該平衡因子來調整其他節點的平衡因子int bf = pSubLR->_bf;// 先對30進行左單旋_RotateL(pParent->_pLeft);// 再對90進行右單旋_RotateR(pParent);if (1 == bf)pSubL->_bf = -1;else if (-1 == bf)pParent->_bf = 1;}};

4. 新節點插入較高右子樹的左側——右左:先右單旋再左單旋

參考左右雙旋。

總結:

假如以pParent為根的子樹不平衡,即pParent的平衡因子為2或者-2,分為以下情況考慮:

1. pParent的平衡因子為2,說明pParent的右子樹高,設pParent的右子樹的根為pSubR。

  • 當pSubR的平衡因子為1時,執行左單旋。
  • 當pSubR的平衡因子為-1時,執行右左單旋。

2.?pParent的平衡因子為-2,說明pParent的左子樹高,設pParent的左子樹的根為pSubL。

  • 當pSubL的平衡因子為-1時,執行右單旋。
  • 當pSubL的平衡因子為1時,執行左右單旋。

旋轉完成后,原pParent為根的子樹高度降低,已經平衡,不需要再向上更新。

2.5 -> AVL樹的驗證

AVL樹是在二叉搜索樹的基礎上加入了平衡性的限制,因此要驗證AVL樹,可以分為兩步:

1. 驗證其為二叉搜索樹

????????如果中序遍歷可以得到一個有序的序列,就說明其為二叉搜索樹。

2. 驗證其為平衡樹

  • 每個節點子樹高度差的絕對值不超過1(注意節點中如果沒有平衡因子)。
  • 節點的平衡因子是否計算正確。
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;template<class T>
struct AVLTreeNode
{AVLTreeNode(const T& data): _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr), _data(data), _bf(0){}AVLTreeNode<T>* _pLeft;   // 該節點的左孩子AVLTreeNode<T>* _pRight;  // 該節點的右孩子AVLTreeNode<T>* _pParent; // 該節點的雙親T _data;int _bf;				  // 該節點的平衡因子bool Insert(const T& data){// 1. 先按照二叉搜索樹的規則將節點插入到AVL樹中// 2. 新節點插入后,AVL樹的平衡性可能會遭到破壞,//	  此時就需要更新平衡因子,并檢測是否破壞了AVL樹的平衡性/*pCur插入后,pParent的平衡因子一定需要調整,在插入之前,pParent的平衡因子分為三種情況:-1,0, 1, 分以下兩種情況:1. 如果pCur插入到pParent的左側,只需給pParent的平衡因子-1即可2. 如果pCur插入到pParent的右側,只需給pParent的平衡因子+1即可此時:pParent的平衡因子可能有三種情況:0,正負1, 正負21. 如果pParent的平衡因子為0,說明插入之前pParent的平衡因子為正負1,插入后被調整成0,此時滿足AVL樹的性質,插入成功2. 如果pParent的平衡因子為正負1,說明插入前pParent的平衡因子一定為0,插入后被更新成正負1,此時以pParent為根的樹的高度增加,需要繼續向上更新3. 如果pParent的平衡因子為正負2,則pParent的平衡因子違反平衡樹的性質,需要對其進行旋轉處理*/while (pParent){// 更新雙親的平衡因子if (pCur == pParent->_pLeft)pParent->_bf--;elsepParent->_bf++;// 更新后檢測雙親的平衡因子if (0 == pParent->_bf){break;}else if (1 == pParent->_bf || -1 == pParent->_bf){// 插入前雙親的平衡因子是0,插入后雙親的平衡因為為1 或者 -1 ,說明以雙親為根的二叉樹// 的高度增加了一層,因此需要繼續向上調整pCur = pParent;pParent = pCur->_pParent;}else{// 雙親的平衡因子為正負2,違反了AVL樹的平衡性,需要對以pParent// 為根的樹進行旋轉處理if (2 == pParent->_bf){// ...}else{// ...}}}return true;}//1. 新節點插入較高左子樹的左側——左左:右單旋/*在插入前,AVL樹是平衡的,新節點插入到30的左子樹(注意:此處不是左孩子)中,30左子樹增加了一層,導致以60為根的二叉樹不平衡,要讓60平衡,只能將60左子樹的高度減少一層,右子樹增加一層,即將左子樹往上提,這樣60轉下來,因為60比30大,只能將其放在30的右子樹,而如果30有右子樹,右子樹根的值一定大于30,小于60,只能將其放在60的左子樹,旋轉完成后,更新節點的平衡因子即可。在旋轉過程中,有以下幾種情況需要考慮:1. 30節點的右孩子可能存在,也可能不存在2. 60可能是根節點,也可能是子樹如果是根節點,旋轉完成后,要更新根節點如果是子樹,可能是某個節點的左子樹,也可能是右子樹*/void _RotateR(PNode pParent){// pSubL: pParent的左孩子// pSubLR: pParent左孩子的右孩子PNode pSubL = pParent->_pLeft;PNode pSubLR = pSubL->_pRight;// 旋轉完成之后,30的右孩子作為雙親的左孩子pParent->_pLeft = pSubLR;// 如果30的左孩子的右孩子存在,更新親雙親if (pSubLR)pSubLR->_pParent = pParent;// 60 作為 30的右孩子pSubL->_pRight = pParent;// 因為60可能是棵子樹,因此在更新其雙親前必須先保存60的雙親PNode pPParent = pParent->_pParent;// 更新60的雙親pParent->_pParent = pSubL;// 更新30的雙親pSubL->_pParent = pPParent;// 如果60是根節點,根新指向根節點的指針if (NULL == pPParent){_pRoot = pSubL;pSubL->_pParent = NULL;}else{// 如果60是子樹,可能是其雙親的左子樹,也可能是右子樹if (pPParent->_pLeft == pParent)pPParent->_pLeft = pSubL;elsepPParent->_pRight = pSubL;}// 根據調整后的結構更新部分節點的平衡因子pParent->_bf = pSubL->_bf = 0;}//3. 新節點插入較高左子樹的右側——左右:先左單旋再右單旋// 旋轉之前,60的平衡因子可能是-1/0/1,旋轉完成之后,根據情況對其他節點的平衡因子進行調整void _RotateLR(PNode pParent){PNode pSubL = pParent->_pLeft;PNode pSubLR = pSubL->_pRight;// 旋轉之前,保存pSubLR的平衡因子,旋轉完成之后,需要根據該平衡因子來調整其他節點的平衡因子int bf = pSubLR->_bf;// 先對30進行左單旋_RotateL(pParent->_pLeft);// 再對90進行右單旋_RotateR(pParent);if (1 == bf)pSubL->_bf = -1;else if (-1 == bf)pParent->_bf = 1;}//驗證是否為AVL樹int _Height(PNode pRoot);bool _IsBalanceTree(PNode pRoot){// 空樹也是AVL樹if (nullptr == pRoot) return true;// 計算pRoot節點的平衡因子:即pRoot左右子樹的高度差int leftHeight = _Height(pRoot->_pLeft);int rightHeight = _Height(pRoot->_pRight);int diff = rightHeight - leftHeight;// 如果計算出的平衡因子與pRoot的平衡因子不相等,或者// pRoot平衡因子的絕對值超過1,則一定不是AVL樹if (diff != pRoot->_bf || (diff > 1 || diff < -1))return false;// pRoot的左和右如果都是AVL樹,則該樹一定是AVL樹return _IsBalanceTree(pRoot->_pLeft) && _IsBalanceTree(pRoot->_pRight);}};

2.6 -> AVL樹的性能

AVL樹是一棵絕對平衡的二叉搜索樹,其要求每個節點的左右子樹高度差的絕對值都不超過1,這樣可以保證查詢時高效的時間復雜度,即O(n)。但是如果要對AVL樹做一些結構修改的操作,性能非常低下,比如:插入時要維護其絕對平衡,旋轉的次數比較多,更差的是在刪除時,有可能一直要讓旋轉持續到根的位置。因此:如果需要一種查詢高效且有序的數據結構,而且數據的個數為靜態的(即不會改變),可以考慮AVL樹。


感謝各位大佬支持!!!

互三啦!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/40166.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/40166.shtml
英文地址,請注明出處:http://en.pswp.cn/web/40166.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《簡歷寶典》02 - 如果你是HR,你會優先打開哪份簡歷?

現在的求職環境不必多說&#xff0c;其實我們大家都還是很清楚的。所以&#xff0c;在這個環境下&#xff0c;寫一份優秀的簡歷&#xff0c;目的與作用也不必多說。那么&#xff0c;這一小節呢&#xff0c;我們先從簡歷這份文檔的文檔名開始說起。 目錄 1 你覺得HR們刷簡歷的時…

【深度學習】圖形模型基礎(5):線性回歸模型第二部分:單變量線性回歸模型

1.引言 在統計學與機器學習的廣闊領域中&#xff0c;線性回歸作為一種基礎而強大的預測技術&#xff0c;其核心在于通過輸入變量&#xff08;或稱預測器、自變量&#xff09;來估計輸出變量&#xff08;響應變量、因變量&#xff09;的連續值。本章聚焦于線性回歸的一個基本但…

Spring-@Component和@Configuration的區別

前言 在Spring框架中&#xff0c;Configuration和Component注解都是用于組件掃描和管理Bean的生命周期&#xff0c;但它們有著不同的用途和應用場景 Component 注解 Component是一個通用的 stereotype 注解&#xff0c;表明一個Java類為Spring框架中的一個Bean組件。Spring會自…

【C++】相機標定源碼筆記- 立體視覺相機的校準和圖像矯正類

類主要用于雙目相機的標定和矯正。它包含了讀取和保存相機模型、計算標定參數以及矯正圖像的功能。通過這些功能&#xff0c;可以實現雙目相機的標定和矯正&#xff0c;從而提高雙目相機的精度和穩定性。 公有函數&#xff1a; 構造函數、帶參構造函數、析構函數、讀取雙目相機…

摩斯邀您參加“WAIC 2024世界人工智能大會”

2024世界人工智能大會暨人工智能全球治理高級別會議&#xff08;簡稱“WAIC 2024”&#xff09;將于7月在上海世博中心、世博展覽館舉行&#xff0c;論壇時間為7月4日-6日&#xff0c;展覽時間為7月5日-7日。大會展覽面積超5.2萬平方米&#xff0c;重點圍繞核心技術、智能終端、…

STM32要學到什么程度才算合格?

在開始前剛好我有一些資料&#xff0c;是我根據網友給的問題精心整理了一份「嵌入式的資料從專業入門到高級教程」&#xff0c; 點個關注在評論區回復“888”之后私信回復“888”&#xff0c;全部無償共享給大家&#xff01;&#xff01;&#xff01; STM32 這玩意兒要學到啥…

今天聊聊AI

AI是在幫助開發者還是取代他們&#xff1f; 在軟件開發領域&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;正在改變開發者的工作方式。無論是代碼生成、錯誤檢測還是自動化測試&#xff0c;AI工具正在成為開發者的得力助手。然而&#xff0c;這也引發了對開發者職業…

vscode 前行復制到下一行

目錄 這個技巧也比較多 選擇 python解釋器 F1 Ctrl Shift P 跳轉上一次編輯 下一次編輯 Ctrl d 會把當前行復制到下一行 步驟1&#xff1a;打開鍵綁定設置 使用VS Code設置換行 這個技巧也比較多 VS Code技巧匯總_vs code反縮進-CSDN博客 選擇 python解釋器 F1 Ctrl Shi…

Java中如何使用 tesseract-ocr 進行圖片文字提取(tesseract、tesseract訓練自己的字庫)

tesseract下載鏈接&#xff1a; github&#xff1a;https://github.com/tesseract-ocr/ db&#xff1a;https://digi.bib.uni-mannheim.de/tesseract/ 文字識別技術在許多領域都有廣泛的應用&#xff0c;例如文檔處理、自動化辦公、移動設備上的文本輸入等。而Tesseract-OCR作…

Python推導式寫出簡潔高效的代碼方法詳解

概要 推導式是Python中一種非常強大的語法特性,允許你用簡潔的語法創建列表、字典、集合等數據結構。使用推導式不僅可以讓代碼更加簡潔和易讀,還能提高代碼的執行效率。本文將詳細介紹Python中的各種推導式,并提供相應的示例代碼,幫助全面掌握這一強大的工具。 列表推導式…

【前端項目筆記】9 數據報表

數據報表 效果展示&#xff1a; 在開發代碼之前新建分支 git checkout -b report 新建分支report git branch 查看分支 git push -u origin report 將本地report分支推送到云端origin并命名為report 通過路由的形式將數據報表加載到頁面中 渲染數據報表基本布局 面包屑導航…

數據洞察:從零到一的數據倉庫與Navicat連接全攻略【實訓Day04】[完結篇]

一、數據分析 1 實現數據倉庫(在hadoop101上) 1) 創建jobdata數據庫 # cd $HIVE_HOME # bin/hive hive>create database jobdata; hive>use jobdata; 2) 創建原始職位數據事實表ods_jobdata_orgin(在hadoop101上) create table ods_jobdata_origin( city string CO…

Keepalived+LVS實現負責均衡,高可用的集群

Keepalived的設計目標是構建高可用的LVS負載均衡群集&#xff0c;可以調用ipvsadm工具來創建虛擬服務器&#xff0c;管理服務器池&#xff0c;而不僅僅用作雙機熱備。使用Keepalived構建LVS群集更加簡便易用&#xff0c;主要優勢體現在&#xff1a;對LVS負責調度器實現熱備切換…

配置并調試后端程序(sql)

1.環境準備 安裝VS Code和Node.js插件&#xff1a;確保你已經安裝了VS Code和Node.js插件。創建launch.json文件&#xff1a;在你的項目中創建一個.vscode文件夾&#xff0c;并在其中創建launch.json文件。添加以下內容&#xff1a; {"version": "0.2.0"…

uniapp 數據父傳子

文章目錄 可能出現的問題 在uni-app中&#xff0c;父組件向子組件傳遞數據主要通過屬性綁定的方式實現。這里提供一個簡單的示例來說明如何進行父傳子的數據傳遞&#xff1a; 父組件 準備數據: 在父組件的data中定義要傳遞的數據。 export default {data() {return {parentMe…

@ControllerAdice統一返回值類型【Spring源碼學習】

我們可以通過在ControllerAdvice注解類上實現ResponseBodyAdvice注解來實現統一返回值類型&#xff1b; 例如統一接口的返回類型為Result類 ControllerAdvice static class MyControllerAdvice implements ResponseBodyAdvice<Object> {Overridepublic boolean supports…

PLC基礎知識

1.PLC中的數據寄存器地址D表示存數據的地方。 2.PLC的物理存儲器的規定&#xff1a;PLC存儲器以字節為單位&#xff08;Byte&#xff09;&#xff0c;存儲單元以位&#xff08;Bit&#xff09;、字節&#xff08;B&#xff0c;8Bit&#xff09;、字&#xff08;W&#xff0c;1…

谷歌優化師招聘網站:夢想啟航的舞臺,實現職業理想的起點

尊敬的夢想實踐者們&#xff0c;歡迎您走進谷歌優化師招聘網站這個充滿魔力的領域。這里不僅是一個招聘平臺&#xff0c;更是您實現職業理想的起點&#xff0c;激發熱情的舞臺。現在&#xff0c;請做好準備&#xff0c;與我們共同揭開這個神秘世界的面紗&#xff01; 夢想啟航…

電子行業MES系統解決方案

工業4.0時代的工業自動化&#xff0c;將在原有自動化技術和架構下&#xff0c;實現集中式控制向分散式增強型控制的基本模式轉變&#xff0c;讓設備從傳感器到因特網的通訊能夠無縫對接&#xff0c;從而建立一個高度靈活的、個性化和數字化、融合了產品與服務的生產模式。在這種…

上海市計算機學會競賽平臺2022年11月月賽丙組染色問題

題目描述 &#x1d45b;n 個點排成一列&#xff0c;需要給每個點一個顏色&#xff0c;顏色有 &#x1d45a;m 種。請問有多少種方法&#xff0c;能使任意相鄰兩個點的顏色均不相同&#xff1f; 輸入格式 兩個整數&#xff1a;表示 &#x1d45b;n 與 &#x1d45a;m 輸出格…