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

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) 
				//                                                                                               
				//                                                                                                                                                         

			   //折线插入:双旋


   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值