C++笔记18•数据结构:AVL树•

news2024/11/15 5:36:00

AVL

简介:
  • 当搜索二叉树退化为单支树时,搜索效率极低,为了使搜索效率高,建立平衡搜索二叉树就需要AVLTree这样的平衡树来解决。
  • 如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡化。
  • 根据节点插入位置的不同,AVL树的旋转分为四种:
1. 新节点插入较高左子树的左侧 --- 左左:右单旋
即: 对60 进行右单旋
2. 新节点插入较高右子树的右侧 --- 右右:左单旋
即: 对30 进行左单旋
3. 新节点插入较高左子树的右侧 --- 左右:先左单旋再右单旋
将双旋变成单旋后再旋转,即: 先对 30 进行左单旋,然后再对 90 进行右单旋 ,旋转完成后再
考虑平衡因子的更新。
4. 新节点插入较高右子树的左侧 --- 右左:先右单旋再左单旋
将双旋变成单旋后再旋转,即: 先对90 进行右单旋,然后再对30 进行左单旋 ,旋转完成后再
考虑平衡因子的更新。
总结:
假如以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为根的子树个高度降低,已经平衡,不需要再向上更新。
5.代码实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <assert.h>
using namespace std;

//二叉搜索树BinarySearchTree
//struct BinarySearchTreeNode

template<class K,class V>
struct AVLTreeNode
{
	AVLTreeNode<K,V>* _left;//一定不要写成BSTreeNode*<K>  _left;  这样编译器无法识别
	AVLTreeNode<K,V>* _right;
	AVLTreeNode<K,V>* _parent;
	pair<K, V> _kv;

	//右子树-左子树的高度差
	int _bf;  // balance factor 平衡因子  	// AVL树并没有规定必须要设计平衡因子  只是一个实现的选择,方便控制平衡

	AVLTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_kv(kv)
		,_bf(0)
	{}
};

template<class K, class V>
class AVLTree
{
	typedef struct AVLTreeNode<K, V> Node;
public:
	bool insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_bf = 0;
			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;
			}
			else
			{
				return false;
			}
		}

		//准备从parent插入
		cur = new Node(kv);
		if (parent->_kv.first > kv.first)//插左子树
		{
			parent->_left = cur;
		}
		else//插右子树
		{
			parent->_right = cur;
		}
		cur->_parent = parent;//新插入的节点指向parent  与父亲相连 (之所以在树节点中设置_parent是为了更新平衡因子方便,可以更快捷的搜索到父亲节点)
		
		//更新平衡因子
		while (parent)//  不要疏忽写成while (cur);  最远可能更新到 根的平衡因子
		{
			if (cur==parent->_left)
			{
				parent->_bf--;
			}
			else
			{
				parent->_bf++;
			}

			//    -1                    0           |           1                          0  
			//   /  \                  / \          |          /  \                      /  \
			//  0       插入右边       0 0          |             0      插入左边        0  0    

			if (parent->_bf == 0)  //插入节点后填上矮的那边, parent_bf: 由-1 or 1  -->> 0  高度不变,更新结束
			{
				break;
			}

			//插入节点后:
			// 若parent_bf: 由0  -->> -1 or 1高度改变,继续更新   
			// 若parent_bf:由-1 or 1  -->> -2 or 2 子树出现不平衡,需要旋转处理(左单旋/右单旋/左右双旋/右左双旋)

			else if (parent->_bf == 1 || parent->_bf == -1)  //插入节点后导致一边变高了,parent_bf: 由0  -->> -1 or 1  高度改变,继续更新parent_bf  (子树的高度变了,继续更新祖先)
			{
				//    0                    0          |             0                         0  
				//   /  \                 / \         |           /  \                       /  \
				//  0    0  插入右边      0  1        |          0    0      插入左边       -1   0   
				//       \                    \       |         /                          / 
				//                             0      |                                   0
			
				cur = cur->_parent;
				parent = parent->_parent;
				//    0                     1          |             0                         -1  
				//   /  \                  / \         |           /  \                       /  \
				//  0    1  更新parent_bf  0  1        |          -1    0   更新parent_bf    -1   0     //直到更新到根节点的祖先时才结束  (_root->_parent==nullptr  进不到while(cur){}循环里,所以结束)    
				//        \                    \       |         /                          / 
				//         0                    0      |        0                          0
			}

			else if (parent->_bf == 2 || parent->_bf == -2)//插入节点后导致本来高一边又变高了,出现了parent_bf=±2,parent_bf: 由-1 or 1  -->> -2 or 2  子树出现不平衡,需要旋转处理(左单旋/右单旋/左右双旋/右左双旋)
			{
				//直线插入:单旋   折线插入:双旋
				
				//直线插入:单旋
				//   a(1)           a(2)                                 b(0)           |   a(-1)       a(-2)                           b(0) 
				//   /  \           / \                                 /   \           |     / \        /  \                           /  \
				//      b(0)          b(1)  a左单旋,更新平衡因子      a(0)  c(0)        |   b(0)       b(-1)   a右单旋,更新平衡因子   c(0)  a(0)    
				//        \             \                                \              |   /          /                                    / 
				//                      c(0)                                            |            c(0)                                        

				if (parent->_bf == 2 && cur->_bf == 1) // 左单旋
				{
					RotateL(parent);//parent左单旋,更新平衡因子
				}
				else if (parent->_bf == -2 && cur->_bf == -1) // 右单旋
				{
					RotateR(parent);//parent右单旋,更新平衡因子
				}

				//折线插入:双旋
				
				//①c为新增节点(左右双旋和右左双旋)
				//   a(-1)           a(-2)                    a(-2)                     c(0)                 |   a(1)           a(2)                    a(2)                        c(0) 
				//   /   \           / \                      /  \                    /      \               |   /  \           / \                      /  \                     /     \  
				//  b(0)          b(1)      b先左单旋       c(-1)      a再右单旋    b(0)    a(0) 更新平衡因子|     b(0)          b(-1)   b先右单旋         c(1)      a再左单旋   a(0)    b(0)     更新平衡因子
				//  /  \          /  \                      /  \                       \    /  \             |     /  \          /  \                      /  \                     \   /      
				//                   c(0)                  b(0)                                              |                  c(0)                          b(0)                                             
				//                   /                        \                                              |                  /         c的右给b的左        /      c的左给a的右                             
				// 上叙情况节点c为新增节点  不管左右双旋   还是右左双旋 最后节点平衡因子都被更新为0    
				
				//②c不是新增节点(左右双旋的两种情况最后的平衡椅子更新都不一样)
				//      a(-1)                           a(-2)
				//   /       \                         /    \                                  a(-2)                                        e(0)
				//  b(0)     d(0)                   b(1)    d(0)                             /      \                                     /       \   
				//  /  \     /  \                   /  \     /  \                         e(-2)     d(0)                                b(0)      a(1) 
				//g(0) e(0) h(0) j(0)             g(-1)e(-1) h(0) j(0)      b先左单旋    /    \     /  \        a再右单旋              /   \       /   \          更新后a的平衡因子为1,b的平衡因子为0,e的平衡因子为0
				// /    / \                      /    /   \                             b(0)  c(0) h(0) j(0)                        g(-1)  f(-1)  c(0)  d(0)
				//i(0)f(0)c(0)                 i(0) f(-1) c(0)                          /   \                                        /      /           /  \  
				//                                  /                                g(-1)  f(-1)                                   i(0)  Q(0)        h(0) j(0)
				//                                 Q(0)                              /      / 
				//                                                                 i(0)  Q(0)
				
				//      a(-1)                           a(-2)
				//   /       \                         /    \                                  a(-2)                                         e(0)
				//  b(0)     d(0)                   b(1)    d(0)                             /      \                                     /         \   
				//  /  \     /  \                   /  \     /  \                         e(-1)     d(0)                                b(-1)        a(0) 
				//g(0) e(0) h(0) j(0)             g(-1)e(1) h(0) j(0)      b先左单旋    /    \      /  \        a再右单旋              /   \       /   \          更新后a的平衡因子为0,b的平衡因子为-1,e的平衡因子为0
				// /    / \                      /    /   \                             b(0)  c(-1)h(0) j(0)                        g(-1)  f(-1)  c(-1)  d(0)
				//i(0)f(0)c(0)                 i(0) f(0) c(-1)                          /  \  /                                     /             /      /   \  
				//                                       /                          g(-1) f(0)Q(0)                                 i(0)         Q(0)    h(0) j(0)
				//                                      Q(0)                           /      
				//                                                                 i(0) 
				// 上叙情况节点c不是新增节点,Q是新增节点  左右双旋/右左双旋 最后节点平衡因子的更新:左右双旋/右左双旋是不同的。上方仅介绍了左右双旋,方法一样

				//③c不是新增节点,q是新增节点(右左双旋的两种情况最后的平衡椅子更新都不一样,与左右双旋的方法一样这里不在介绍)
				
				//       a(1)                                       a(2)                               a(2)                                 e(0) 
				//    /       \                                   /      \                             /    \                               /   \      
				//  b(0)       d(0)                            b(0)      d(-1)                       b(0)   e(1)                        a(0)   d(1) 
				//           /      \                                   /     \      d先右旋                /  \           a再左旋      /   \   /  \          更新后a的平衡因子为0,d的平衡因子为1,e的平衡因子为0
				//         e(0)    c(1)                                e(-1)   c(0)                       q(0)  d(1)                 b(0)  q(0)   c(0)
				//                                                     /                                         /  \
				//                                                    q(0)                                          c(0)
				                                                      
				//       a(1)                                       a(2)                               a(2)                                 e(0) 
				//    /       \                                   /      \                             /    \                               /   \
				//  b(0)       d(0)                            b(0)      d(-1)                       b(0)   e(2)                        a(-1)   d(0) 
				//           /      \                                   /     \      d先右旋                /  \           a再左旋      /  \    /  \          更新后a的平衡因子为-1,d的平衡因子为0,e的平衡因子为0
				//         e(0)    c(1)                                e(1)   c(-1)                           d(0)                    b(0)    q(0) c(0)
				//                                                        \                                   /  \
				//                                                        q(0)                             q(0  c(0) 
				//                                                                                               
				//                                                                                                                                                         

			   //折线插入:双旋
				else if (parent->_bf == -2 && cur->_bf == 1) // 左右单旋
				{
					RotateLR(parent);//从parent处左右双旋
				}
				else if (parent->_bf == 2 && cur->_bf == -1) // 右左单旋
				{
					RotateRL(parent);//从parent处右左双旋
				}

				break;
			}
	
			else
			{
				assert(false);// 插入之前AVL树就存在不平衡的子树,|平衡因子| >= 2的节点   直接断言报错
			}

		}

		return true;

	}

	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	bool IsBalanceTree()
	{
		return _IsBalanceTree(_root);
	}

	int Height()
	{
		return _Height(_root);
	}

private:
	Node* _root = nullptr;

	void RotateL(Node* parent)//左单旋
	{
		Node* ppNode = parent->_parent;
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		
		parent->_right = subRL;
		if (subRL)
		{
			subRL->_parent = parent;
		}

		subR->_left = parent;
		parent->_parent = subR;
	
		if (parent == _root)
		{
			_root = subR;
			_root->_parent = nullptr;//subR->_parent = nullptr; //不可以只写这一句  如果parent是根 必须要更新_root; 加上 _root = subR;
		}
		else
		{
			if (parent == ppNode->_left)
			{
				ppNode->_left = subR;
			}
			else  //parent == ppNode->_right
			{
				ppNode->_right = subR;
			}
			subR->_parent = ppNode;
		}
		//更新平衡因子
		parent->_bf = 0;
		subR->_bf = 0;
	}
	void RotateR(Node* parent)//右单旋
	{
		Node* ppNode = parent->_parent;
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR)
		{
			subLR->_parent= parent;
		}

		subL->_right = parent;
		parent->_parent = subL;

		if (parent == _root)
		{
			_root = subL;
			_root->_parent = nullptr;//subR->_parent = nullptr; //不可以只写这一句  如果parent是根 必须要更新_root; 加上 _root = subR;
		}
		else
		{
			if (parent == ppNode->_left)
			{
				ppNode->_left = subL;
			}
			else  //parent == ppNode->_right
			{
				ppNode->_right = subL;
			}
			subL->_parent = ppNode;
		}
		//更新平衡因子
		parent->_bf = 0;
		subL->_bf = 0;
	}

	void RotateLR(Node* parent)//左右双旋
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->_bf;

		RotateL(subL);//RotateL(parent->_left);
		RotateR(parent);

		//更新平衡因子
		if (bf == 0)
		{
			parent->_bf = 0;
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 1;
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = 0;
			subL->_bf = -1;
			subLR->_bf = 0;
		}
		else
		{
			//subLR->_bf 旋转之前就有问题
			assert(false);
		}
	}

	void RotateRL(Node* parent)//右左双旋
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;

		RotateR(subR);//RotateL(parent->_right);
		RotateL(parent);

		//更新平衡因子
		if (bf == 0)
		{
			parent->_bf = 0;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 0;
			subR->_bf = 1;
			subRL->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = -1;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else
		{
			//subRL->_bf 旋转之前就有问题
			assert(false);
		}
	}

	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 lh = _Height(root->_left);//lh   leftheight  左树高度
		int rh = _Height(root->_right);//rh   rightheight  右树高度

		return lh > rh ? lh + 1 : rh + 1;
	}

	bool _IsBalanceTree(Node* root)
	{
		// 空树也是AVL树
		if (nullptr == root)
			return true;

		// 计算pRoot节点的平衡因子:即pRoot左右子树的高度差
		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);
		int diff = rightHeight - leftHeight;

		// 如果计算出的平衡因子与pRoot的平衡因子不相等,或者
		// pRoot平衡因子的绝对值超过1,则一定不是AVL树
		if (abs(diff) >= 2)
		{
			cout << root->_kv.first << "节点平衡因子异常" << endl;
			return false;
		}

		if (diff != root->_bf)
		{
			cout << root->_kv.first << "节点平衡因子不符合实际" << endl;
			return false;
		}

		// pRoot的左和右如果都是AVL树,则该树一定是AVL树
		return _IsBalanceTree(root->_left)
			&& _IsBalanceTree(root->_right);
	}
};

void TestAVLTree1()
{
	//int a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
	int a[] = { 30,29,28,27,26,25,24,11,8,7,6,5,4,3,2,1 };
	AVLTree<int, int> t;
	for (auto e : a)
	{
		t.insert(make_pair(e, e));
	}
	t.InOrder();
	cout<<t.IsBalanceTree()<<endl;
}
void TestAVLTree2()
{
	int a[] = { 30,29,28,27,26,25,24,11,8,7,6,5,4,3,2,1 };
	AVLTree<int, int> t;
	for (auto e : a)
	{
		bool res = t.insert(make_pair(e, e));
		if (res)
		{
			cout << "Inserted: " << e << endl;
		}
		else
		{
			cout << "Failed to insert: " << e << endl;
		}
	}
	t.InOrder();
	cout << t.IsBalanceTree() << endl;
}


int main()
{
	//TestAVLTree1();
	TestAVLTree2();
	return 0;
}
			//插入节点后:
			// 若parent_bf: 由0  -->> -1 or 1高度改变,继续更新   
			// 若parent_bf:由-1 or 1  -->> -2 or 2 子树出现不平衡,需要旋转处理(左单旋/右单旋/左右双旋/右左双旋)

			else if (parent->_bf == 1 || parent->_bf == -1)  //插入节点后导致一边变高了,parent_bf: 由0  -->> -1 or 1  高度改变,继续更新parent_bf  (子树的高度变了,继续更新祖先)
			{
				//    0                    0          |             0                         0  
				//   /  \                 / \         |           /  \                       /  \
				//  0    0  插入右边      0  1         |          0    0      插入左边       -1   0   
				//       \                    \       |         /                          / 
				//                             0      |                                   0
			
				cur = cur->_parent;
				parent = parent->_parent;
				//    0                     1          |             0                         -1  
				//   /  \                  / \         |           /  \                       /  \
				//  0    1  更新parent_bf  0  1        |          -1    0   更新parent_bf    -1   0     //直到更新到根节点的祖先时才结束  (_root->_parent==nullptr  进不到while(cur){}循环里,所以结束)    
				//        \                    \       |         /                          / 
				//         0                    0      |        0                          0
			}

			else if (parent->_bf == 2 || parent->_bf == -2)//插入节点后导致本来高一边又变高了,出现了parent_bf=±2,parent_bf: 由-1 or 1  -->> -2 or 2  子树出现不平衡,需要旋转处理(左单旋/右单旋/左右双旋/右左双旋)
			{
				//直线插入:单旋   折线插入:双旋
				
				//直线插入:单旋
				//   a(1)           a(2)                                 b(0)           |   a(-1)       a(-2)                           b(0) 
				//   /  \           / \                                 /   \           |     / \        /  \                           /  \
				//      b(0)          b(1)  a左单旋,更新平衡因子      a(0)  c(0)        |   b(0)       b(-1)   a右单旋,更新平衡因子   c(0)  a(0)    
				//        \             \                                \              |   /          /                                    / 
				//                      c(0)                                            |            c(0)                                        

				if (parent->_bf == 2 && cur->_bf == 1) // 左单旋
				{
					RotateL(parent);//parent左单旋,更新平衡因子
				}
				else if (parent->_bf == -2 && cur->_bf == -1) // 右单旋
				{
					RotateR(parent);//parent右单旋,更新平衡因子
				}

				//折线插入:双旋
				
				//①c为新增节点(左右双旋和右左双旋)
				//   a(-1)           a(-2)                    a(-2)                     c(0)                 |   a(1)           a(2)                    a(2)                        c(0) 
				//   /   \           / \                      /  \                    /      \               |   /  \           / \                      /  \                     /     \  
				//  b(0)          b(1)      b先左单旋       c(-1)      a再右单旋    b(0)    a(0) 更新平衡因子|     b(0)          b(-1)   b先右单旋         c(1)      a再左单旋   a(0)    b(0)     更新平衡因子
				//  /  \          /  \                      /  \                       \    /  \             |     /  \          /  \                      /  \                     \   /      
				//                   c(0)                  b(0)                                              |                  c(0)                          b(0)                                             
				//                   /                        \                                              |                  /         c的右给b的左        /      c的左给a的右                             
				// 上叙情况节点c为新增节点  不管左右双旋   还是右左双旋 最后节点平衡因子都被更新为0    
				
				//②c不是新增节点(左右双旋的两种情况最后的平衡椅子更新都不一样)
				//      a(-1)                           a(-2)
				//   /       \                         /    \                                  a(-2)                                        e(0)
				//  b(0)     d(0)                   b(1)    d(0)                             /      \                                     /       \   
				//  /  \     /  \                   /  \     /  \                         e(-2)     d(0)                                b(0)      a(1) 
				//g(0) e(0) h(0) j(0)             g(-1)e(-1) h(0) j(0)      b先左单旋    /    \     /  \        a再右单旋              /   \       /   \          更新后a的平衡因子为1,b的平衡因子为0,e的平衡因子为0
				// /    / \                      /    /   \                             b(0)  c(0) h(0) j(0)                        g(-1)  f(-1)  c(0)  d(0)
				//i(0)f(0)c(0)                 i(0) f(-1) c(0)                          /   \                                        /      /           /  \  
				//                                  /                                g(-1)  f(-1)                                   i(0)  Q(0)        h(0) j(0)
				//                                 Q(0)                              /      / 
				//                                                                 i(0)  Q(0)
				
				//      a(-1)                           a(-2)
				//   /       \                         /    \                                  a(-2)                                         e(0)
				//  b(0)     d(0)                   b(1)    d(0)                             /      \                                     /         \   
				//  /  \     /  \                   /  \     /  \                         e(-1)     d(0)                                b(-1)        a(0) 
				//g(0) e(0) h(0) j(0)             g(-1)e(1) h(0) j(0)      b先左单旋    /    \      /  \        a再右单旋              /   \       /   \          更新后a的平衡因子为0,b的平衡因子为-1,e的平衡因子为0
				// /    / \                      /    /   \                             b(0)  c(-1)h(0) j(0)                        g(-1)  f(-1)  c(-1)  d(0)
				//i(0)f(0)c(0)                 i(0) f(0) c(-1)                          /  \  /                                     /             /      /   \  
				//                                       /                          g(-1) f(0)Q(0)                                 i(0)         Q(0)    h(0) j(0)
				//                                      Q(0)                           /      
				//                                                                 i(0) 
				// 上叙情况节点c不是新增节点,Q是新增节点  左右双旋/右左双旋 最后节点平衡因子的更新:左右双旋/右左双旋是不同的。上方仅介绍了左右双旋,方法一样

				//③c不是新增节点,q是新增节点(右左双旋的两种情况最后的平衡椅子更新都不一样,与左右双旋的方法一样这里不在介绍)
				
				//       a(1)                                       a(2)                               a(2)                                 e(0) 
				//    /       \                                   /      \                             /    \                               /   \      
				//  b(0)       d(0)                            b(0)      d(-1)                       b(0)   e(1)                        a(0)   d(1) 
				//           /      \                                   /     \      d先右旋                /  \           a再左旋      /   \   /  \          更新后a的平衡因子为0,d的平衡因子为1,e的平衡因子为0
				//         e(0)    c(1)                                e(-1)   c(0)                       q(0)  d(1)                 b(0)  q(0)   c(0)
				//                                                     /                                         /  \
				//                                                    q(0)                                          c(0)
				                                                      
				//       a(1)                                       a(2)                               a(2)                                 e(0) 
				//    /       \                                   /      \                             /    \                               /   \
				//  b(0)       d(0)                            b(0)      d(-1)                       b(0)   e(2)                        a(-1)   d(0) 
				//           /      \                                   /     \      d先右旋                /  \           a再左旋      /  \    /  \          更新后a的平衡因子为-1,d的平衡因子为0,e的平衡因子为0
				//         e(0)    c(1)                                e(1)   c(-1)                           d(0)                    b(0)    q(0) c(0)
				//                                                        \                                   /  \
				//                                                        q(0)                             q(0  c(0) 
				//                                                                                               
				//                                                                                                                                                         

			   //折线插入:双旋


   

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

领夹麦克风哪个好,领夹麦哪个牌子音质好,音质最好的麦克风推荐

在数字化内容创作的浪潮中&#xff0c;无线领夹麦克风以其便携高效的特点&#xff0c;成为了音频捕捉领域的热门选择。然而&#xff0c;每款产品都有其两面性&#xff0c;无线领夹麦克风在提供便利的同时&#xff0c;也潜藏着一些不容忽视的使用困扰。今天&#xff0c;我们就来…

【AI】张量的秩(阶)与矩阵的秩和阶的区别

在阅读MindSpore文档时&#xff0c;笔者对这段话不太理解&#xff0c;遂求助ChatGPT. 矩阵的秩是矩阵中线性无关的行或者列&#xff0c;矩阵的阶就是矩阵中的行数和列数。 而张量的秩和阶是一个概念&#xff0c;指的是张量的维度&#xff08;是1维的&#xff0c;二维的还是高维…

CRM软件的演进:从传统到连接型CRM

1、CRM定义与分类 1.1CRM的定义 CRM,英文Customer Relationship Management的缩写&#xff0c;中文全称为客户关系管理。通常情况下&#xff0c;人们通常用CRM直接表达客户关系管理软件系统——一个以客户为中心的专门用于管理与客户关系的软件工具&#xff0c;以确保与客户…

AI算力池化平台加速智能驾驶技术发展

1886年&#xff0c;世界上第一辆汽车诞生。在随后的一百多年时间里&#xff0c;汽车成为广泛用于社会经济生活多种领域的重要交通运输工具&#xff0c;极大地推动了人类社会经济的发展。进入新世纪&#xff0c;汽车的电动化、智能化日趋明显。 在汽车智能化方面&#xff0c;最…

YOLOv8改进 | 模块缝合 | C2f 融合RFAConv增强感受野空间特征 【完整代码 + 自研创新】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

龙胆草:恰似神秘星辰般的独特花语与奇幻传说

龙胆草&#xff0c;宛如大自然中一颗璀璨的神秘星辰。其不仅拥有着如诗般“恋上不快乐得你”的独特花语&#xff0c;背后更隐藏着中国和日本等充满奇幻色彩的传说故事。从曾童与蛇娘的传奇到日本兔子掘草根救人的奇闻&#xff0c;龙胆草承载着深厚的文化底蕴。快来一同探寻龙胆…

探索全光网技术 | 全光网产品解决方案整理-(宇洪科技)

探索全光网技术 |全光网产品解决方案整理-宇洪科技 目录 一、数据中心场景1、方案概述2、方案需求3、相关产品4、产品推荐5、方案价值 二、教育场景1、方案概述2、方案需求3、相关产品4、方案价值 三、医疗场景1、方案概述2、方案需求3、相关产品4、方案价值 注&#xff1a;本文…

LeetCode题练习与总结:天际线问题--218

一、题目描述 城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度&#xff0c;请返回 由这些建筑物形成的 天际线 。 每个建筑物的几何信息由数组 buildings 表示&#xff0c;其中三元组 buildings[i] [lefti, righti, heighti…

Peet‘s Coffee与观测云跨界合作,为伙伴们呈现双重喜悦

随着中秋佳节的临近&#xff0c;国内监控观测行业的领军企业观测云&#xff0c;携手国际知名咖啡品牌 Peets Coffee&#xff0c;共同打造了一款专为中秋佳节定制的特别礼盒&#xff0c;这份礼盒不仅是对传统节日的现代诠释&#xff0c;更是对雅致生活的深情致敬。 Peets Coffe…

【专题】2024年8月医药行业报告合集汇总PDF分享(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p37621 在科技飞速发展的当今时代&#xff0c;医药行业作为关乎人类生命健康的重要领域&#xff0c;正处于前所未有的变革浪潮之中。数智医疗服务的崛起&#xff0c;为医疗模式带来了全新的转变&#xff0c;开启了医疗服务的新时代。…

伴奏提取消除人声如何操作?轻松几步玩转音乐世界

你是否梦想着独自演绎一曲&#xff0c;或是进行个性化的混音创作&#xff0c;却又希望摆脱原唱声音的干扰&#xff1f;那么&#xff0c;学会免费伴奏提取就显得尤为关键。 在这篇文章中&#xff0c;我将为你展示四种简单易学的方法&#xff0c;让你能够轻松地从歌曲中提取出伴…

手机上将mp4转换成amv怎么转?视频转换,3个方法拿捏

在这个社交媒体时代&#xff0c;视频已经成为人们传递信息、表达情感的重要方式之一。然而&#xff0c;不同的设备和平台对视频格式的要求不尽相同&#xff0c;这就需要我们不时地进行视频格式转换&#xff0c;以便在不同的场景中更好地展示和分享我们的作品。 对视频格式转换…

物联网之ESP32控制GPIO输出点亮LED、网页控制LED开关

MENU 前言原理GPIO引脚LED 硬件电路设计软件设计1、点亮一颗LED2、闪烁的LED3、网页控制LED开关 前言 不论学习什么单片机&#xff0c;最简单的外设莫过于IO口的高低电平控制LED&#xff0c;本文介绍如何使用Arduino控制ESP32的GPIO输出。通过本文的学习&#xff0c;掌握一定的…

Qt26代理delegate

代理delegate mainwindowmainwindow.hmainwindow.cpp datedelegatedatedelegate.hdatedelegate.cpp combodelegatecombodelegate.hcombodelegate.cpp spindelegatespindelegate.hspindelegate.cpp main.cpp运行图 mainwindow mainwindow.h #ifndef MAINWINDOW_H #define MAIN…

Java8新特性-Optional的使用

写在前面 最开始学java的时候&#xff0c;总能听到别人说java8的新特性&#xff0c;比如lambda表达式&#xff0c;stream流等等。但是第一次接触Optional是在公司前辈的代码中看到的。最开始我还以为是公司自己的工具类&#xff0c;也没太注意。后来才知道他也是java8最重要的…

西安十大产业园,哪一个将成为你事业的新起点?

每个人在追求事业成功的过程中&#xff0c;都在寻找那个能够助力自己腾飞的平台&#xff0c;而西安的十大产业园无疑提供了丰富多样的选择&#xff1a; 一、西安国际数字影像产业园 1. 园区概况 西安国际数字影像产业园是西安乃至西北地区在数字影像产业领域的重要基地&#…

基于视觉-语言模型的机器人任务规划:ViLaIn框架解析

目录 一、引言二、ViLaln框架介绍总体框架概述对象估计器初始状态估计器目标估计器纠错重提示机制&#xff08;CR&#xff09; 参考文献 一、引言 随着机器人技术的不断发展&#xff0c;如何通过自然语言指令引导机器人执行任务成为了一个重要的研究方向。自然语言作为人与机器…

mysql连接oceanbase数据库集群+租户

mysql集成的有连接oceanbase数据库的方式&#xff0c;所以只需要对参数进行修改即可。 url: jdbc:mysql://[ip地址]:[端口]/[数据库]?useUnicodetrue&characterEncodingUTF-8&serverTimezoneUTC //其他参数根据需求设置username: [用户名][租户名]#[集群名]password: …

【CTF Web】BUUCTF Upload-Labs-Linux Pass-10 Writeup(文件上传+PHP+扩展名双写绕过)

Upload-Labs-Linux 1 点击部署靶机。 简介 upload-labs是一个使用php语言编写的&#xff0c;专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关&#xff0c;每一关都包含着不同上传方式。 注意 1.每一关没有固定的…

springboot+vue+mybatisjsp广播剧制作订阅系统+PPT+论文+讲解+售后

随着世界经济信息化、全球化的到来和互联网的飞速发展&#xff0c;推动了各行业的改革。若想达到安全&#xff0c;快捷的目的&#xff0c;就需要拥有信息化的组织和管理模式&#xff0c;建立一套合理、动态的、交互友好的、高效的广播剧制作订阅系统。当前的信息管理存在工作效…