вторник, 24 июня 2025 г.

Красно-черное дерево на Си

 

Красно-черное дерево на Си

Красно-черное дерево - это самобалансирующееся бинарное дерево поиска, которое гарантирует логарифмическую высоту дерева и эффективные операции вставки, удаления и поиска.

Вот пример реализации красно-черного дерева на языке Си:

c
#include <stdio.h>
#include <stdlib.h>

// Определение цвета узла
typedef enum { RED, BLACK } Color;

// Структура узла красно-черного дерева
typedef struct Node {
    int data;
    Color color;
    struct Node *left, *right, *parent;
} Node;

// Создание нового узла
Node* createNode(int data) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->color = RED; // Новый узел всегда красный
    newNode->left = newNode->right = newNode->parent = NULL;
    return newNode;
}

// Вспомогательная функция для левого поворота
void leftRotate(Node **root, Node *x) {
    Node *y = x->right;
    x->right = y->left;
    
    if (y->left != NULL)
        y->left->parent = x;
    
    y->parent = x->parent;
    
    if (x->parent == NULL)
        *root = y;
    else if (x == x->parent->left)
        x->parent->left = y;
    else
        x->parent->right = y;
    
    y->left = x;
    x->parent = y;
}

// Вспомогательная функция для правого поворота
void rightRotate(Node **root, Node *y) {
    Node *x = y->left;
    y->left = x->right;
    
    if (x->right != NULL)
        x->right->parent = y;
    
    x->parent = y->parent;
    
    if (y->parent == NULL)
        *root = x;
    else if (y == y->parent->left)
        y->parent->left = x;
    else
        y->parent->right = x;
    
    x->right = y;
    y->parent = x;
}

// Функция для восстановления свойств красно-черного дерева после вставки
void fixInsert(Node **root, Node *z) {
    while (z != *root && z->parent->color == RED) {
        if (z->parent == z->parent->parent->left) {
            Node *y = z->parent->parent->right;
            
            if (y != NULL && y->color == RED) {
                // Дядя красный - случай 1
                z->parent->color = BLACK;
                y->color = BLACK;
                z->parent->parent->color = RED;
                z = z->parent->parent;
            } else {
                if (z == z->parent->right) {
                    // Дядя черный и z - правый ребенок - случай 2
                    z = z->parent;
                    leftRotate(root, z);
                }
                // Дядя черный и z - левый ребенок - случай 3
                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                rightRotate(root, z->parent->parent);
            }
        } else {
            // Симметричный случай
            Node *y = z->parent->parent->left;
            
            if (y != NULL && y->color == RED) {
                z->parent->color = BLACK;
                y->color = BLACK;
                z->parent->parent->color = RED;
                z = z->parent->parent;
            } else {
                if (z == z->parent->left) {
                    z = z->parent;
                    rightRotate(root, z);
                }
                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                leftRotate(root, z->parent->parent);
            }
        }
    }
    (*root)->color = BLACK; // Корень всегда черный
}

// Вставка узла в красно-черное дерево
void insert(Node **root, int data) {
    Node *z = createNode(data);
    Node *y = NULL;
    Node *x = *root;
    
    // Обычная вставка в бинарное дерево поиска
    while (x != NULL) {
        y = x;
        if (z->data < x->data)
            x = x->left;
        else
            x = x->right;
    }
    
    z->parent = y;
    
    if (y == NULL)
        *root = z;
    else if (z->data < y->data)
        y->left = z;
    else
        y->right = z;
    
    // Восстановление свойств красно-черного дерева
    fixInsert(root, z);
}

// Вспомогательная функция для вывода дерева (обход в порядке in-order)
void inOrder(Node *root) {
    if (root == NULL)
        return;
    
    inOrder(root->left);
    printf("%d(%s) ", root->data, root->color == RED ? "RED" : "BLACK");
    inOrder(root->right);
}

// Основная функция для демонстрации
int main() {
    Node *root = NULL;
    
    // Вставка элементов
    insert(&root, 10);
    insert(&root, 20);
    insert(&root, 30);
    insert(&root, 15);
    insert(&root, 25);
    insert(&root, 5);
    insert(&root, 35);
    
    // Вывод дерева
    printf("In-order traversal of the constructed tree:\n");
    inOrder(root);
    printf("\n");
    
    return 0;
}

Объяснение кода:

  1. Структура узла: Каждый узел содержит данные, цвет (красный или черный), указатели на левого и правого потомков, а также на родителя.

  2. Вращения:

    • leftRotate и rightRotate - операции, которые помогают сохранять баланс дерева.

  3. Вставка:

    • Сначала выполняется стандартная вставка как в бинарное дерево поиска.

    • Затем вызывается fixInsert для восстановления свойств красно-черного дерева.

  4. Восстановление свойств (fixInsert):

    • Исправляет возможные нарушения свойств красно-черного дерева после вставки.

    • Рассматривает три основных случая в зависимости от цвета дяди текущего узла.

  5. Свойства красно-черного дерева:

    • Каждый узел либо красный, либо черный.

    • Корень всегда черный.

    • Все листья (NIL) черные.

    • У красного узла оба потомка черные.

    • Все пути от узла до его листьев содержат одинаковое количество черных узлов.

Этот код демонстрирует базовые операции красно-черного дерева. Для полной реализации нужно также добавить функции удаления узла и обработки других случаев балансировки.

New chat
AI-generated, for reference only

Комментариев нет:

Отправить комментарий