数据结构 红黑树笔记(附源代码)

目录

1.红黑树的特点

2.红黑树的旋转

3.红黑树的插入

4.红黑树的插入维护

5.红黑树的删除

6.红黑树的删除维护

4.源代码


1.红黑树的特点

首先是一颗二叉搜索树所有的左子树小于根,所有的右子树大于根),但在这个基础上引入了红河两种颜色,相当于给每个节点打上flag,后续动态平衡时起到非常重要的作用,针对颜色而言;其中根结点和叶子(NULL)节点必须是黑色的,红色结点的左右孩子必须是黑色的,也就是不可以存在连续的两个红色结点从任意结点到叶所有的路径上黑色的结点数量必须是相同的。

如下是红黑树的数据结构定义

#define RED 1
#define BLACK 2

typedef int DataType;

typedef struct rbtreenode {
	DataType data;
	void* value;
	unsigned char color;	    
	struct rbtreenode* left;  //左孩子
	struct rbtreenode* right; //右孩子
	struct rbtreenode* parent;//父结点
}RBTreeNode;

typedef struct rbtree {
	RBTreeNode* nil;  //叶子(NULL)
	RBTreeNode* root; //根
}RBTree;

RBTree* InitRBTree() {
	RBTree* T = (RBTree *)malloc(sizeof(RBTree));
	if (!T) return;
	T->nil = (RBTreeNode *)malloc(sizeof(RBTreeNode));
	if (!T->nil) return;
	T->nil->color = BLACK;
	T->root = T->nil;
	return T;
}
RBTreeNode* InitRBTreeNode() {
	RBTreeNode* node = (RBTreeNode*)malloc(sizeof(RBTreeNode));
	if (!node) return;
	node->value = NULL;
	return node;
}

2.红黑树的旋转

左旋(Left Rotation)以及 右旋(Right Rotation)

/*
* left rotate  right rotate 
* x->left=a x->right=y y->left=b y->right=c
* y->left=x y->right=c x->left=a x->right=b 
*/
void rbtree_left_rotate(RBTree *T,RBTreeNode *x) {
	RBTreeNode* y = x->right;
	x->right = y->left;
	if (y->left != T->nil) {
		y->left->parent = x;
	}

	y->parent = x->parent;
	if (x->parent == T->nil) {
		T->root = y;
	}
	else if (x == x->parent->left) {
		x->parent->left = y;
	}
	else {
		x->parent->right = y;
	}

	y->left = x;
	x->parent = y;
}

void rbtree_right_rotate(RBTree* T, RBTreeNode* y) {
	RBTreeNode* x = y->left;
	y->left = x->right;
	if (x->right != T->nil) {
		x->right->parent = y;
	}

	x->parent = y->parent;
	if (y->parent == T->nil) {
		T->root = x;
	}
	else if (y == y->parent->right) {
		y->parent->right = x;
	}
	else {
		y->parent->left = x;
	}

	x->right = y;
	y->parent = x;
}

3.红黑树的插入

红黑树规定,插入的节点必须是红色的。而且,二叉查找树中新插入的节点都是放在叶子节点上,方法相对常规。

void rbtree_insert(RBTree *T,RBTreeNode *z) {
	RBTreeNode* y = T->nil;
	RBTreeNode* x = T->root;

	while (x != T->nil) {
		y = x;
		if (z->data < x->data) {
			x = x->left;
		}
		else if (z->data > x->data) {
			x = x->right;
		}
		else break;
	}

	z->parent = y;
	if (y == T->nil) {
		T->root = z;
	}
	else if (z->data < y->data) {
		y->left = z;
	}
	else {
		y->right = z;
	}

	z->color = RED;
	z->left = z->right = T->nil;

	rbtree_insert_fixup(T, z);
}

4.红黑树的插入维护(重点)

1.插入节点的叔叔节点是红色的 父节点和叔叔节点变成黑色 爷爷节点变成红色 下次迭代从爷爷节点开始

2.叔叔节点是黑色 插入节点是父节点的左孩子 父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋


3.叔叔节点是黑色 插入节点是父节点的右孩子 绕着父节点做一次左旋 父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋

/* 插入后维护
* 1.插入节点的叔叔节点是红色的
*   父节点和叔叔节点变成黑色 爷爷节点变成红色 下次迭代从爷爷节点开始
* 2.叔叔节点是黑色 插入节点是父节点的左孩子
*   父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋
* 3.叔叔节点是黑色 插入节点是父节点的右孩子
*   绕着父节点做一次左旋
*   父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋
*/
void rbtree_insert_fixup(RBTree* T, RBTreeNode* z) {
	while (z->parent->color == RED) {
		if (z->parent == z->parent->parent->left) {
			//叔叔节点拿出来
			RBTreeNode* y = z->parent->parent->right;
			if (y->color == RED) {
				y->color = z->parent->color = BLACK;
				z->parent->parent->color = RED;
				z = z->parent->parent;
			}
			else {
				if (z == z->parent->right) {
					z = z->parent;
					rbtree_left_rotate(T, z);
				}
				z->parent->color = BLACK;
				z->parent->parent->color = RED;
				rbtree_right_rotate(T, z->parent->parent);
			}
		}
		else {
			RBTreeNode* y = z->parent->parent->left;
			if (y->color == RED) {
				z->parent->color = y->color = BLACK;
				z->parent->parent->color = RED;
				z = z->parent->parent;
			}
			else {
				if (z == z->parent->left) {
					z = z->parent;
					rbtree_right_rotate(T, z);
				}
				z->parent->color = BLACK;
				z->parent->parent->color = RED;
				rbtree_left_rotate(T,z->parent->parent);
			}
		}
	}
	T->root->color = BLACK;
}

5.红黑树的删除

//delrbtree
/*
* 红黑树的删除操作根据儿子节点的孩子节点个数,分为三种情况
* 1.没有孩子 即为叶结点。直接把父结点的对应儿子指针设为NULL就可以了.
* 2.1个孩子  把父结点的相应儿子指针指向儿子的孩子,然后删除儿子节点就可以了.
* 3.2个孩子  用后继节点替换待删除的节点,然后删除这个后继节点,问题就转化成了上述两点
*/
RBTreeNode* rbtree_mini(RBTree* T, RBTreeNode* x) {
	while (x->left != T->nil) {
		x = x->left;
	}
	return x;
}

RBTreeNode* rbtree_count(RBTree* T, RBTreeNode* x) {
	RBTreeNode* y = x->parent;
	if (x->right != T->nil) {
		return rbtree_mini(T,x->right);
	}
	return y;
}

RBTreeNode* rbtree_delete(RBTree *T,RBTreeNode *z) {
	RBTreeNode* y = T->nil;
	RBTreeNode* x = T->nil;
	
	if (z->left == T->nil || z->right ==T->nil) {
		y = z;
	}
	else {
		y = rbtree_count(T, z);
	}

	if (y->left != T->nil) {
		x = y->left;
	}
	else if (y->right != T->nil) {
		x = y->right;
	}

	x->parent = y->parent;
	if (y->parent == T->nil) {
		T->root = x;
	}
	else if (y == y->parent->left) {
		y->parent->left = x;
	}
	else {
		y->parent->right = y;
	}

	if (y !=z ) {
		z->data = y->data;
		z->value = y->value;
	}

	if (y->color == BLACK) {
		rbtree_delete_fixup(T,x);
	}

	return y;
}

6.红黑树的删除维护(重点)

1.x的兄弟节点w是红色的
*   将w涂黑,将x->p涂红,然后把兄弟节点绕着父节点左旋,
*   最后把w重新做指向,令w=x->p->right,
*   这样w变成了黑色结点(根据红黑树的性质,必定是黑色的),
*   调整结束以后,情况1可能会变成情况2、3、4.


* 2.x的兄弟w是黑色的,且w的两个儿子都是黑色
* 直接把兄弟节点变成红色,再将指向x的指针指向父节点,
* 然后根据父亲节点的颜色决定是否进行下一步调整,如果父亲节点的颜色为红色,
* 就把父亲节点变成黑色,即可结束调整;如果父亲节点的颜色是黑色,
* 那就要根据调整结束后的状态做下一步调整,可能会变成情况1、2、3、4.


* 3.x的兄弟w是黑色的,而w的左孩子为红色,右孩子为黑色
* 那么我们将w->left涂黑,然后将w涂红,再将w->left绕着w做右旋,然后情况3就会变成情况4.


* 4.x的兄弟w是黑色的,而w的左孩子为黑色,右孩子为红色
* 把兄弟节点w换成父节点的颜色,并把父亲节点和w-right涂黑,然后把兄弟节点w绕着父节点做一次左旋,
* 完成之后的结构刚好满足红黑树的性质.

/*
* 删除后维护
* 1.x的兄弟节点w是红色的
*   将w涂黑,将x->p涂红,然后把兄弟节点绕着父节点左旋,
*   最后把w重新做指向,令w=x->p->right,
*   这样w变成了黑色结点(根据红黑树的性质,必定是黑色的),
*   调整结束以后,情况1可能会变成情况2、3、4.
*
* 2.x的兄弟w是黑色的,且w的两个儿子都是黑色
* 直接把兄弟节点变成红色,再将指向x的指针指向父节点,
* 然后根据父亲节点的颜色决定是否进行下一步调整,如果父亲节点的颜色为红色,
* 就把父亲节点变成黑色,即可结束调整;如果父亲节点的颜色是黑色,
* 那就要根据调整结束后的状态做下一步调整,可能会变成情况1、2、3、4.
*
* 3.x的兄弟w是黑色的,而w的左孩子为红色,右孩子为黑色
* 那么我们将w->left涂黑,然后将w涂红,再将w->left绕着w做右旋,然后情况3就会变成情况4.
*
* 4.x的兄弟w是黑色的,而w的左孩子为黑色,右孩子为红色
* 把兄弟节点w换成父节点的颜色,并把父亲节点和w-right涂黑,然后把兄弟节点w绕着父节点做一次左旋,
* 完成之后的结构刚好满足红黑树的性质.
*/
void rbtree_delete_fixup(RBTree* T, RBTreeNode* x) {
	while ((x != T->root) && (x->color == BLACK)) {
		// 此if与相应的else是镜像的
		if (x == x->parent->left) {
			// 找到兄弟节点
			RBTreeNode* w = x->parent->right;
			// 情况1:兄弟节点为红色
			if (w->color == RED) {
				// 兄弟节点变成黑色
				w->color = BLACK;
				// 父节点变成红色
				x->parent->color = RED;

				// 父节点做左旋
				rbtree_left_rotate(T, x->parent);
				// 重新设置x的兄弟节点
				w = x->parent->right;
			}
			// 情况2:兄弟节点是黑色的,且兄弟的左孩子和右孩子都是黑色
			if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
				//  兄弟节点变成红色
				w->color = RED;
				// 将指向x的指针指向其父节点
				x = x->parent;
			}
			else {
				// 情况3:x的兄弟节点是黑色的,兄弟的左孩子是红色,右孩子是黑色
				if (w->right->color == BLACK) {
					// 将左孩子涂黑
					w->left->color = BLACK;
					// 将兄弟节点变红
					w->color = RED;
					// 对兄弟节点右旋
					rbtree_right_rotate(T, w);
					// 重新设置x的兄弟节点
					w = x->parent->right;
				}
				// 情况4:x的兄弟节点是黑色;x的兄弟节点的右孩子是红色的
				// 将兄弟节点换成父节点的颜色
				w->color = x->parent->color;
				// 把父节点和兄弟节点的右孩子涂黑
				x->parent->color = BLACK;
				w->right->color = BLACK;
				// 对父节点做左旋
				rbtree_left_rotate(T, x->parent);
				// 设置x指针,指向根节点
				x = T->root;
			}
		}
		else {
			RBTreeNode* w = x->parent->left;
			if (w->color == RED) {
				w->color = BLACK;
				x->parent->color = RED;
				rbtree_right_rotate(T, x->parent);
				w = x->parent->left;
			}

			if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
				w->color = RED;
				x = x->parent;
			}
			else {
				if (w->left->color == BLACK) {
					w->right->color = BLACK;
					w->color = RED;
					rbtree_left_rotate(T, w);
					w = x->parent->left;
				}

				w->color = x->parent->color;
				x->parent->color = BLACK;
				w->left->color = BLACK;
				rbtree_right_rotate(T, x->parent);

				x = T->root;
			}
		}
	}
	// 继承节点变为黑色,为了弥补失去的黑高
	x->color = BLACK;
}

7.源代码

#include <stdio.h>
#include <stdlib.h>
//RED BLACK TREE
/*
* 节点是红色或者黑色
* 根是黑色的
* 所有叶子都是黑色的,并且是NIL节点
* 每个红色节点的两个子节点都是黑色的
* 并且红色的叶子结点不能连续
* 从任意一个节点到其每个叶子的路径黑色节点都相同
*/
#define RED 1
#define BLACK 2

typedef int DataType;

typedef struct rbtreenode {
	DataType data;
	void* value;
	unsigned char color;	    
	struct rbtreenode* left;  //左孩子
	struct rbtreenode* right; //右孩子
	struct rbtreenode* parent;//父结点
}RBTreeNode;

typedef struct rbtree {
	RBTreeNode* nil;  //叶子(NULL)
	RBTreeNode* root; //根
}RBTree;

RBTree* InitRBTree() {
	RBTree* T = (RBTree *)malloc(sizeof(RBTree));
	if (!T) return;
	T->nil = (RBTreeNode *)malloc(sizeof(RBTreeNode));
	if (!T->nil) return;
	T->nil->color = BLACK;
	T->root = T->nil;
	return T;
}
RBTreeNode* InitRBTreeNode() {
	RBTreeNode* node = (RBTreeNode*)malloc(sizeof(RBTreeNode));
	if (!node) return;
	node->value = NULL;
	return node;
}
/*
* left rotate  right rotate 
* x->left=a x->right=y y->left=b y->right=c
* y->left=x y->right=c x->left=a x->right=b 
*/
void rbtree_left_rotate(RBTree *T,RBTreeNode *x) {
	RBTreeNode* y = x->right;
	x->right = y->left;
	if (y->left != T->nil) {
		y->left->parent = x;
	}

	y->parent = x->parent;
	if (x->parent == T->nil) {
		T->root = y;
	}
	else if (x == x->parent->left) {
		x->parent->left = y;
	}
	else {
		x->parent->right = y;
	}

	y->left = x;
	x->parent = y;
}

void rbtree_right_rotate(RBTree* T, RBTreeNode* y) {
	RBTreeNode* x = y->left;
	y->left = x->right;
	if (x->right != T->nil) {
		x->right->parent = y;
	}

	x->parent = y->parent;
	if (y->parent == T->nil) {
		T->root = x;
	}
	else if (y == y->parent->right) {
		y->parent->right = x;
	}
	else {
		y->parent->left = x;
	}

	x->right = y;
	y->parent = x;
}

/* 插入后维护
* 1.插入节点的叔叔节点是红色的
*   父节点和叔叔节点变成黑色 爷爷节点变成红色 下次迭代从爷爷节点开始
* 2.叔叔节点是黑色 插入节点是父节点的左孩子
*   父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋
* 3.叔叔节点是黑色 插入节点是父节点的右孩子
*   绕着父节点做一次左旋
*   父亲节点变成黑色 爷爷节点变成红色 最后绕着爷爷节点做一次右旋
*/
void rbtree_insert_fixup(RBTree* T, RBTreeNode* z) {
	while (z->parent->color == RED) {
		if (z->parent == z->parent->parent->left) {
			//叔叔节点拿出来
			RBTreeNode* y = z->parent->parent->right;
			if (y->color == RED) {
				y->color = z->parent->color = BLACK;
				z->parent->parent->color = RED;
				z = z->parent->parent;
			}
			else {
				if (z == z->parent->right) {
					z = z->parent;
					rbtree_left_rotate(T, z);
				}
				z->parent->color = BLACK;
				z->parent->parent->color = RED;
				rbtree_right_rotate(T, z->parent->parent);
			}
		}
		else {
			RBTreeNode* y = z->parent->parent->left;
			if (y->color == RED) {
				z->parent->color = y->color = BLACK;
				z->parent->parent->color = RED;
				z = z->parent->parent;
			}
			else {
				if (z == z->parent->left) {
					z = z->parent;
					rbtree_right_rotate(T, z);
				}
				z->parent->color = BLACK;
				z->parent->parent->color = RED;
				rbtree_left_rotate(T,z->parent->parent);
			}
		}
	}
	T->root->color = BLACK;
}

void rbtree_insert(RBTree *T,RBTreeNode *z) {
	RBTreeNode* y = T->nil;
	RBTreeNode* x = T->root;

	while (x != T->nil) {
		y = x;
		if (z->data < x->data) {
			x = x->left;
		}
		else if (z->data > x->data) {
			x = x->right;
		}
		else break;
	}

	z->parent = y;
	if (y == T->nil) {
		T->root = z;
	}
	else if (z->data < y->data) {
		y->left = z;
	}
	else {
		y->right = z;
	}

	z->color = RED;
	z->left = z->right = T->nil;

	rbtree_insert_fixup(T, z);
}

//*******************************************************************************
/*
* 删除后维护
* 1.x的兄弟节点w是红色的
*   将w涂黑,将x->p涂红,然后把兄弟节点绕着父节点左旋,
*   最后把w重新做指向,令w=x->p->right,
*   这样w变成了黑色结点(根据红黑树的性质,必定是黑色的),
*   调整结束以后,情况1可能会变成情况2、3、4.
*
* 2.x的兄弟w是黑色的,且w的两个儿子都是黑色
* 直接把兄弟节点变成红色,再将指向x的指针指向父节点,
* 然后根据父亲节点的颜色决定是否进行下一步调整,如果父亲节点的颜色为红色,
* 就把父亲节点变成黑色,即可结束调整;如果父亲节点的颜色是黑色,
* 那就要根据调整结束后的状态做下一步调整,可能会变成情况1、2、3、4.
*
* 3.x的兄弟w是黑色的,而w的左孩子为红色,右孩子为黑色
* 那么我们将w->left涂黑,然后将w涂红,再将w->left绕着w做右旋,然后情况3就会变成情况4.
*
* 4.x的兄弟w是黑色的,而w的左孩子为黑色,右孩子为红色
* 把兄弟节点w换成父节点的颜色,并把父亲节点和w-right涂黑,然后把兄弟节点w绕着父节点做一次左旋,
* 完成之后的结构刚好满足红黑树的性质.
*/
void rbtree_delete_fixup(RBTree* T, RBTreeNode* x) {
	while ((x != T->root) && (x->color == BLACK)) {
		// 此if与相应的else是镜像的
		if (x == x->parent->left) {
			// 找到兄弟节点
			RBTreeNode* w = x->parent->right;
			// 情况1:兄弟节点为红色
			if (w->color == RED) {
				// 兄弟节点变成黑色
				w->color = BLACK;
				// 父节点变成红色
				x->parent->color = RED;

				// 父节点做左旋
				rbtree_left_rotate(T, x->parent);
				// 重新设置x的兄弟节点
				w = x->parent->right;
			}
			// 情况2:兄弟节点是黑色的,且兄弟的左孩子和右孩子都是黑色
			if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
				//  兄弟节点变成红色
				w->color = RED;
				// 将指向x的指针指向其父节点
				x = x->parent;
			}
			else {
				// 情况3:x的兄弟节点是黑色的,兄弟的左孩子是红色,右孩子是黑色
				if (w->right->color == BLACK) {
					// 将左孩子涂黑
					w->left->color = BLACK;
					// 将兄弟节点变红
					w->color = RED;
					// 对兄弟节点右旋
					rbtree_right_rotate(T, w);
					// 重新设置x的兄弟节点
					w = x->parent->right;
				}
				// 情况4:x的兄弟节点是黑色;x的兄弟节点的右孩子是红色的
				// 将兄弟节点换成父节点的颜色
				w->color = x->parent->color;
				// 把父节点和兄弟节点的右孩子涂黑
				x->parent->color = BLACK;
				w->right->color = BLACK;
				// 对父节点做左旋
				rbtree_left_rotate(T, x->parent);
				// 设置x指针,指向根节点
				x = T->root;
			}
		}
		else {
			RBTreeNode* w = x->parent->left;
			if (w->color == RED) {
				w->color = BLACK;
				x->parent->color = RED;
				rbtree_right_rotate(T, x->parent);
				w = x->parent->left;
			}

			if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
				w->color = RED;
				x = x->parent;
			}
			else {
				if (w->left->color == BLACK) {
					w->right->color = BLACK;
					w->color = RED;
					rbtree_left_rotate(T, w);
					w = x->parent->left;
				}

				w->color = x->parent->color;
				x->parent->color = BLACK;
				w->left->color = BLACK;
				rbtree_right_rotate(T, x->parent);

				x = T->root;
			}
		}
	}
	// 继承节点变为黑色,为了弥补失去的黑高
	x->color = BLACK;
}

//*******************************************************************************

//delrbtree
/*
* 红黑树的删除操作根据儿子节点的孩子节点个数,分为三种情况
* 1.没有孩子 即为叶结点。直接把父结点的对应儿子指针设为NULL就可以了.
* 2.1个孩子  把父结点的相应儿子指针指向儿子的孩子,然后删除儿子节点就可以了.
* 3.2个孩子  用后继节点替换待删除的节点,然后删除这个后继节点,问题就转化成了上述两点
*/
RBTreeNode* rbtree_mini(RBTree* T, RBTreeNode* x) {
	while (x->left != T->nil) {
		x = x->left;
	}
	return x;
}

RBTreeNode* rbtree_count(RBTree* T, RBTreeNode* x) {
	RBTreeNode* y = x->parent;
	if (x->right != T->nil) {
		return rbtree_mini(T,x->right);
	}
	return y;
}

RBTreeNode* rbtree_delete(RBTree *T,RBTreeNode *z) {
	RBTreeNode* y = T->nil;
	RBTreeNode* x = T->nil;
	
	if (z->left == T->nil || z->right ==T->nil) {
		y = z;
	}
	else {
		y = rbtree_count(T, z);
	}

	if (y->left != T->nil) {
		x = y->left;
	}
	else if (y->right != T->nil) {
		x = y->right;
	}

	x->parent = y->parent;
	if (y->parent == T->nil) {
		T->root = x;
	}
	else if (y == y->parent->left) {
		y->parent->left = x;
	}
	else {
		y->parent->right = y;
	}

	if (y !=z ) {
		z->data = y->data;
		z->value = y->value;
	}

	if (y->color == BLACK) {
		rbtree_delete_fixup(T,x);
	}

	return y;
}

RBTreeNode* rbtree_search(RBTree* T, DataType data) {
	RBTreeNode* node = T->root;
	while (node != T->nil) {
		if (data < node->data) {
			node = node->left;
		}
		else if (data > node->data) {
			node = node->right;
		}
		else {
			return node;
		}
	}
	return T->nil;
}

void rbtree_leader(RBTree* T, RBTreeNode* node) {
	if (node != T->nil) {
		printf("data = %d   color = %d\n", node->data, node->color);
		rbtree_leader(T, node->left);
		rbtree_leader(T, node->right);
	}
}
void rbtree_inorder(RBTree *T,RBTreeNode *node) {
	if (node != T->nil) {
		rbtree_inorder(T, node->left);
		printf("data = %d   color = %d\n",node->data,node->color);
		rbtree_inorder(T, node->right);
	}
}
void rbtree_lastder(RBTree* T, RBTreeNode* node) {
	if (node != T->nil) {
		rbtree_lastder(T, node->left);
		rbtree_lastder(T, node->right);
		printf("data = %d   color = %d\n", node->data, node->color);
	}
}

int main() {
	int keyArray[20] = { 24,25,13,35,23, 26,67,47,38,98, 20,19,17,49,12, 21,9,18,14,15 };
	RBTree* T = InitRBTree();
	for (int i = 0; i<sizeof(keyArray)/sizeof(keyArray[0]); ++i) {
		RBTreeNode* node = InitRBTreeNode();
		node->data = keyArray[i];
		rbtree_insert(T,node);
	}
	rbtree_inorder(T,T->root);
	printf("----------------------------------------\n");
	RBTreeNode* node = rbtree_search(T, 23);
	RBTreeNode* cur = rbtree_delete(T, node);
	free(cur);
	rbtree_inorder(T, T->root);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

7yewh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值