C语言之平衡二叉树怎么实现

发布时间:2023-04-25 16:16:07 作者:iii
来源:亿速云 阅读:151

C语言之平衡二叉树怎么实现

目录

  1. 引言
  2. 平衡二叉树的基本概念
  3. 平衡二叉树的类型
  4. AVL树的实现
  5. 红黑树的实现
  6. 平衡二叉树的应用
  7. 总结

引言

平衡二叉树是一种特殊的二叉搜索树,它通过保持树的平衡性来确保树的高度始终在可控范围内,从而保证查找、插入和删除等操作的时间复杂度为O(log n)。本文将详细介绍如何在C语言中实现平衡二叉树,重点讨论AVL树和红黑树这两种常见的平衡二叉树类型。

平衡二叉树的基本概念

二叉搜索树

二叉搜索树(Binary Search Tree, BST)是一种特殊的二叉树,它满足以下性质:

二叉搜索树的查找、插入和删除操作的平均时间复杂度为O(log n),但在最坏情况下(如树退化为链表),时间复杂度会退化为O(n)。

平衡二叉树的定义

平衡二叉树(Balanced Binary Tree)是一种特殊的二叉搜索树,它通过某种机制保持树的平衡性,使得树的高度始终在可控范围内。常见的平衡二叉树包括AVL树和红黑树。

平衡因子

平衡因子(Balance Factor)是衡量二叉树平衡性的一个重要指标。对于AVL树来说,平衡因子定义为某个节点的左子树高度减去右子树高度。平衡因子的绝对值不超过1时,树被认为是平衡的。

平衡二叉树的类型

AVL树

AVL树是最早发明的自平衡二叉搜索树之一。它通过旋转操作来保持树的平衡性,确保每个节点的平衡因子的绝对值不超过1。

红黑树

红黑树是一种更为复杂的自平衡二叉搜索树,它通过颜色标记和旋转操作来保持树的平衡性。红黑树的平衡性要求比AVL树宽松,但在实际应用中,红黑树的性能通常与AVL树相当。

AVL树的实现

节点结构定义

在C语言中,AVL树的节点可以定义如下:

typedef struct AVLNode {
    int data;
    struct AVLNode *left;
    struct AVLNode *right;
    int height; // 节点的高度
} AVLNode;

插入操作

AVL树的插入操作与普通二叉搜索树的插入操作类似,但在插入后需要检查树的平衡性,并通过旋转操作来恢复平衡。

AVLNode* insert(AVLNode* node, int data) {
    if (node == NULL) {
        AVLNode* newNode = (AVLNode*)malloc(sizeof(AVLNode));
        newNode->data = data;
        newNode->left = NULL;
        newNode->right = NULL;
        newNode->height = 1;
        return newNode;
    }

    if (data < node->data) {
        node->left = insert(node->left, data);
    } else if (data > node->data) {
        node->right = insert(node->right, data);
    } else {
        return node; // 不允许插入重复数据
    }

    node->height = 1 + max(height(node->left), height(node->right));

    int balance = getBalance(node);

    // 左左情况
    if (balance > 1 && data < node->left->data) {
        return rightRotate(node);
    }

    // 右右情况
    if (balance < -1 && data > node->right->data) {
        return leftRotate(node);
    }

    // 左右情况
    if (balance > 1 && data > node->left->data) {
        node->left = leftRotate(node->left);
        return rightRotate(node);
    }

    // 右左情况
    if (balance < -1 && data < node->right->data) {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }

    return node;
}

删除操作

AVL树的删除操作同样需要维护树的平衡性。删除节点后,需要检查树的平衡性,并通过旋转操作来恢复平衡。

AVLNode* deleteNode(AVLNode* root, int data) {
    if (root == NULL) {
        return root;
    }

    if (data < root->data) {
        root->left = deleteNode(root->left, data);
    } else if (data > root->data) {
        root->right = deleteNode(root->right, data);
    } else {
        if ((root->left == NULL) || (root->right == NULL)) {
            AVLNode* temp = root->left ? root->left : root->right;

            if (temp == NULL) {
                temp = root;
                root = NULL;
            } else {
                *root = *temp;
            }

            free(temp);
        } else {
            AVLNode* temp = minValueNode(root->right);
            root->data = temp->data;
            root->right = deleteNode(root->right, temp->data);
        }
    }

    if (root == NULL) {
        return root;
    }

    root->height = 1 + max(height(root->left), height(root->right));

    int balance = getBalance(root);

    // 左左情况
    if (balance > 1 && getBalance(root->left) >= 0) {
        return rightRotate(root);
    }

    // 左右情况
    if (balance > 1 && getBalance(root->left) < 0) {
        root->left = leftRotate(root->left);
        return rightRotate(root);
    }

    // 右右情况
    if (balance < -1 && getBalance(root->right) <= 0) {
        return leftRotate(root);
    }

    // 右左情况
    if (balance < -1 && getBalance(root->right) > 0) {
        root->right = rightRotate(root->right);
        return leftRotate(root);
    }

    return root;
}

旋转操作

AVL树通过旋转操作来恢复平衡。常见的旋转操作包括左旋和右旋。

AVLNode* rightRotate(AVLNode* y) {
    AVLNode* x = y->left;
    AVLNode* T2 = x->right;

    x->right = y;
    y->left = T2;

    y->height = max(height(y->left), height(y->right)) + 1;
    x->height = max(height(x->left), height(x->right)) + 1;

    return x;
}

AVLNode* leftRotate(AVLNode* x) {
    AVLNode* y = x->right;
    AVLNode* T2 = y->left;

    y->left = x;
    x->right = T2;

    x->height = max(height(x->left), height(x->right)) + 1;
    y->height = max(height(y->left), height(y->right)) + 1;

    return y;
}

红黑树的实现

节点结构定义

在C语言中,红黑树的节点可以定义如下:

typedef enum { RED, BLACK } Color;

typedef struct RBNode {
    int data;
    Color color;
    struct RBNode *left;
    struct RBNode *right;
    struct RBNode *parent;
} RBNode;

插入操作

红黑树的插入操作比AVL树复杂,因为需要维护红黑树的性质。插入节点后,可能需要进行颜色调整和旋转操作。

void insert(RBNode** root, int data) {
    RBNode* newNode = createNode(data);
    RBNode* parent = NULL;
    RBNode* current = *root;

    while (current != NULL) {
        parent = current;
        if (newNode->data < current->data) {
            current = current->left;
        } else {
            current = current->right;
        }
    }

    newNode->parent = parent;

    if (parent == NULL) {
        *root = newNode;
    } else if (newNode->data < parent->data) {
        parent->left = newNode;
    } else {
        parent->right = newNode;
    }

    newNode->left = NULL;
    newNode->right = NULL;
    newNode->color = RED;

    fixViolation(root, newNode);
}

删除操作

红黑树的删除操作同样复杂,删除节点后可能需要进行颜色调整和旋转操作。

void deleteNode(RBNode** root, int data) {
    RBNode* node = search(*root, data);
    if (node == NULL) {
        return;
    }

    RBNode* child;
    RBNode* parent;
    Color originalColor = node->color;

    if (node->left == NULL) {
        child = node->right;
        transplant(root, node, node->right);
    } else if (node->right == NULL) {
        child = node->left;
        transplant(root, node, node->left);
    } else {
        RBNode* successor = minimum(node->right);
        originalColor = successor->color;
        child = successor->right;

        if (successor->parent == node) {
            if (child != NULL) {
                child->parent = successor;
            }
        } else {
            transplant(root, successor, successor->right);
            successor->right = node->right;
            successor->right->parent = successor;
        }

        transplant(root, node, successor);
        successor->left = node->left;
        successor->left->parent = successor;
        successor->color = node->color;
    }

    if (originalColor == BLACK) {
        fixDeleteViolation(root, child);
    }

    free(node);
}

颜色调整与旋转

红黑树的颜色调整和旋转操作是维护红黑树性质的关键。

void fixViolation(RBNode** root, RBNode* node) {
    RBNode* parent = NULL;
    RBNode* grandparent = NULL;

    while ((node != *root) && (node->color != BLACK) && (node->parent->color == RED)) {
        parent = node->parent;
        grandparent = parent->parent;

        if (parent == grandparent->left) {
            RBNode* uncle = grandparent->right;

            if (uncle != NULL && uncle->color == RED) {
                grandparent->color = RED;
                parent->color = BLACK;
                uncle->color = BLACK;
                node = grandparent;
            } else {
                if (node == parent->right) {
                    leftRotate(root, parent);
                    node = parent;
                    parent = node->parent;
                }

                rightRotate(root, grandparent);
                swapColors(parent, grandparent);
                node = parent;
            }
        } else {
            RBNode* uncle = grandparent->left;

            if (uncle != NULL && uncle->color == RED) {
                grandparent->color = RED;
                parent->color = BLACK;
                uncle->color = BLACK;
                node = grandparent;
            } else {
                if (node == parent->left) {
                    rightRotate(root, parent);
                    node = parent;
                    parent = node->parent;
                }

                leftRotate(root, grandparent);
                swapColors(parent, grandparent);
                node = parent;
            }
        }
    }

    (*root)->color = BLACK;
}

void leftRotate(RBNode** root, RBNode* x) {
    RBNode* 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(RBNode** root, RBNode* y) {
    RBNode* 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->right) {
        y->parent->right = x;
    } else {
        y->parent->left = x;
    }

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

平衡二叉树的应用

平衡二叉树广泛应用于需要高效查找、插入和删除操作的场景,如数据库索引、内存管理、编译器符号表等。AVL树和红黑树在实际应用中各有优劣,选择合适的平衡二叉树类型取决于具体的应用场景和性能需求。

总结

平衡二叉树通过保持树的平衡性,确保了查找、插入和删除操作的高效性。本文详细介绍了如何在C语言中实现AVL树和红黑树这两种常见的平衡二叉树类型,并讨论了它们的应用场景。希望本文能为读者提供有关平衡二叉树的深入理解,并帮助读者在实际项目中应用这些数据结构。

推荐阅读:
  1. 如何使用C语言实现自动售货机
  2. 如何分析C/C++指针、函数、结构体和共用体

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c语言

上一篇:QTreeWidget中MainWindow窗体布局器不起作用怎么解决

下一篇:vue中怎么使用watch监听对象中某个属性

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》