红黑树是一种自平衡的二叉查找树,它通过对节点的颜色进行约束,确保了树的高度始终保持在log(n)级别,其中n是树中节点的数量。红黑树的特点是:
- 每个节点或者是红色,或者是黑色。
- 根节点是黑色。
- 每个叶子节点(NIL节点,空节点)是黑色。
- 如果一个节点是红色的,则它的子节点必须是黑色的。
- 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
以下是红黑树主要功能的实现原理和C语言代码实现,每行代码都有详细注释: - 创建节点:为新节点分配内存,并初始化其属性。
// 定义红黑树节点的颜色
#define RED 0
#define BLACK 1
// 定义红黑树节点结构体
typedef struct Node {
int data; // 节点存储的数据
int color; // 节点的颜色
struct Node *left; // 左子节点
struct Node *right; // 右子节点
struct Node *parent; // 父节点
} Node;
// 创建一个新的红黑树节点
Node* createNode(int data) {
Node* node = (Node*)malloc(sizeof(Node)); // 为新节点分配内存
node->data = data; // 初始化节点数据
node->color = RED; // 新创建的节点默认为红色
node->left = NULL; // 初始化左子节点为NULL
node->right = NULL; // 初始化右子节点为NULL
node->parent = NULL; // 初始化父节点为NULL
return node; // 返回新创建的节点
}
- 插入节点:将新节点插入到红黑树中,并维护红黑树的性质。
// 插入节点到红黑树
void insertNode(Node** root, Node* node) {
// 如果树为空,直接将新节点作为根节点
if (*root == NULL) {
*root = node;
node->color = BLACK; // 根节点必须是黑色
return;
}
// 找到新节点的插入位置
Node* current = *root;
Node* parent = NULL;
while (current != NULL) {
parent = current;
if (node->data < current->data) {
current = current->left;
} else {
current = current->right;
}
}
// 将新节点插入到红黑树中
node->parent = parent;
if (node->data < parent->data) {
parent->left = node;
} else {
parent->right = node;
}
// 维护红黑树的性质
fixInsert(node);
}
- 维护红黑树的性质:在插入节点后,通过一系列的旋转和颜色变换来维护红黑树的性质。
// 维护红黑树的性质
void fixInsert(Node* node) {
// 如果新节点是根节点,直接将其颜色设置为黑色
if (node->parent == NULL) {
node->color = BLACK;
return;
}
// 如果父节点是黑色,不需要调整
if (node->parent->color == BLACK) {
return;
}
// 获取祖父节点
Node* grandparent = node->parent->parent;
// 获取叔叔节点
Node* uncle = NULL;
if (grandparent != NULL) {
if (node->parent == grandparent->left) {
uncle = grandparent->right;
} else {
uncle = grandparent->left;
}
}
// 如果叔叔节点是红色,需要调整
if (uncle != NULL && uncle->color == RED) {
node->parent->color = BLACK;
uncle->color = BLACK;
grandparent->color = RED;
fixInsert(grandparent);
} else {
// 如果叔叔节点是黑色,需要进行旋转操作
if (node == node->parent->right && node->parent == grandparent->left) {
rotateLeft(node->parent);
node = node->left;
} else if (node == node->parent->left && node->parent == grandparent->right) {
rotateRight(node->parent);
node = node->right;
}
node->parent->color = BLACK;
grandparent->color = RED;
if (node == node->parent->left) {
rotateRight(grandparent);
} else {
rotateLeft(grandparent);
}
}
}
- 旋转操作:左旋转和右旋转是红黑树调整树结构以保持平衡的关键操作。
// 左旋转
void rotateLeft(Node* node) {
Node* rightChild = node->right;
node->right = rightChild->left;
if (node->right != NULL) {
node->right->parent = node;
}
rightChild->parent = node->parent;
if (node->parent == NULL) {
root = rightChild;
} else if (node == node->parent->left) {
node->parent->left = rightChild;
} else {
node->parent->right = rightChild;
}
rightChild->left = node;
node->parent = rightChild;
}
// 右旋转
void rotateRight(Node* node) {
Node* leftChild = node->left;
node->left = leftChild->right;
if (node->left != NULL) {
node->left->parent = node;
}
leftChild->parent = node->parent;
if (node->parent == NULL) {
root = leftChild;
} else if (node == node->parent->left) {
node->parent->left = leftChild;
} else {
node->parent->right = leftChild;
}
leftChild->right = node;
node->parent = leftChild;
}
- 打印红黑树:以图形化的方式打印红黑树,以便于观察树的结构。
// 打印红黑树
void printTree(Node* node, int space) {
int i;
if (node == NULL) {
return;
}
space += 10;
printTree(node->right, space);
printf("\n");
for (i = 10; i < space; i++) {
printf(" ");
}
printf("%d(%d)\n", node->data, node->color);
printTree(node->left, space);
}
以上代码实现了一个简单的红黑树,包括创建节点、插入节点、维护红黑树的性质、旋转操作和打印树的功能。在插入节点时,会调用fixInsert
函数来维护红黑树的性质。代码中还包括了左旋转和右旋转的函数,这是红黑树调整树结构以保持平衡的关键操作。