数据结构----二叉树

数据结构基础:树与二叉树详解

目录

  1. 树(Tree

    • 定义
    • 相关概念
    • 结构特点
    • 代码案例
  2. 二叉树(Binary Tree

    • 定义
    • 相关概念
    • 结构特点
    • 代码案例
  3. 二叉树的高级概念

    • 完全二叉树
    • 满二叉树
    • 二叉搜索树
    • 平衡二叉树
    • 红黑树
    • 线索二叉树

树(Tree)

1.1 定义

树是一种模拟具有层次关系的数据集合的非线性数据结构。它由节点和连接节点的边组成,具有一个称为根的起始节点,每个节点可以有零个或多个子节点,但只能有一个父节点。

1.2 相关概念

  • 根节点:树的顶端节点,是树的入口点。
  • 叶子节点:没有子节点的节点,表示树的末端。
  • 子树:由节点及其所有后代组成的树的一部分。
  • 深度:从根节点到特定节点的路径长度。
  • 高度:树中最长路径的长度,通常指从根到最远叶子的距离。

1.3 结构特点

树的结构特点确保了数据的有序性和高效的数据访问能力。每个节点只有一个父节点,保证了树的层次性;没有循环路径,避免了数据的重复和冗余。

1.4 代码案例

以下是树的基本操作的C语言实现,包括树节点的创建和子节点的添加。

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

// 树节点定义
typedef struct TreeNode {
    int data;
    struct TreeNode** children; // 指针数组,指向子节点
    int numChildren;            // 子节点数量
} TreeNode;

// 创建树节点
TreeNode* createTreeNode(int data) {
    TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
    if (node) {
        node->data = data;
        node->children = NULL;
        node->numChildren = 0;
    }
    return node;
}

// 添加子节点
void addTreeNodeChild(TreeNode* parent, TreeNode* child) {
    if (parent && child) {
        parent->children = (TreeNode**)realloc(parent->children, 
                                               sizeof(TreeNode*) * (parent->numChildren + 1));
        parent->children[parent->numChildren++] = child;
    }
}

// 释放树内存
void freeTree(TreeNode* node) {
    if (node) {
        for (int i = 0; i < node->numChildren; ++i) {
            freeTree(node->children[i]);
        }
        free(node->children);
        free(node);
    }
}

// 树的其他操作(例如遍历)可以在这里继续添加...

二叉树(Binary Tree)

2.1 定义

二叉树是树的一种特殊形式,其中每个节点最多有两个子节点,分别称为左子节点和右子节点。这种结构限制使得二叉树在搜索、排序和许多其他算法中非常有用。

2.2 相关概念

二叉树的遍历是学习和实现二叉树的关键部分,包括:

  • 前序遍历:首先访问根节点,然后递归地遍历左子树和右子树。
  • 中序遍历:首先递归地遍历左子树,然后访问根节点,最后递归地遍历右子树。
  • 后序遍历:首先递归地遍历左子树和右子树,然后访问根节点。
  • 层次遍历:按照层次顺序从上到下,从左到右访问节点。

2.3 结构特点

二叉树的结构特点包括:

  • 每个节点最多有两个子节点,提供了一种高效的数据存储方式。
  • 左子树和右子树的区分使得二叉树在实现算法时更加灵活。

2.4 代码案例

以下是二叉树的基本操作的C语言实现,包括节点的创建和各种遍历方法。

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

// 二叉树节点定义
typedef struct BinaryTreeNode {
    int data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
} BinaryTreeNode;

// 创建二叉树节点
BinaryTreeNode* createBinaryTreeNode(int data) {
    BinaryTreeNode* node = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
    if (node) {
        node->data = data;
        node->left = NULL;
        node->right = NULL;
    }
    return node;
}

// 前序遍历
void preOrderTraversal(BinaryTreeNode* node) {
    if (node != NULL) {
        printf("%d ", node->data);
        preOrderTraversal(node->left);
        preOrderTraversal(node->right);
    }
}

// 中序遍历
void inOrderTraversal(BinaryTreeNode* node) {
    if (node != NULL) {
        inOrderTraversal(node->left);
        printf("%d ", node->data);
        inOrderTraversal(node->right);
    }
}

// 后序遍历
void postOrderTraversal(BinaryTreeNode* node) {
    if (node != NULL) {
        postOrderTraversal(node->left);
        postOrderTraversal(node->right);
        printf("%d ", node->data);
    }
}

// 层次遍历(广度优先遍历)
void levelOrderTraversal(BinaryTreeNode* root) {
    if (root == NULL) return;
    // 这里需要包含queue.h头文件或使用C++ STL中的queue
    queue<BinaryTreeNode*> q;
    q.push(root);
    while (!q.empty()) {
        BinaryTreeNode* current = q.front();
        q.pop();
        printf("%d ", current->data);
        if (current->left != NULL) q.push(current->left);
        if (current->right != NULL) q.push(current->right);
    }
}

// 释放二叉树内存
void freeBinaryTree(BinaryTreeNode* node) {
    if (node) {
        freeBinaryTree(node->left);
        freeBinaryTree(node->right);
        free(node);
    }
}

// 二叉树的其他操作可以在这里继续添加...

3. 二叉树的高级概念

3.1 完全二叉树(Complete Binary Tree)

完全二叉树是一种特殊二叉树,除了最后一层外,每层都被完全填满,最后一层的节点尽可能地靠左。

代码案例

完全二叉树通常使用数组来表示,以下是创建和初始化一个完全二叉树的代码示例:

// 完全二叉树的数组表示
int completeBinaryTree[] = {10, 6, 15, 3, 8, 20, 1, 7};
int size = sizeof(completeBinaryTree) / sizeof(completeBinaryTree[0]);

// 打印完全二叉树的层序遍历
void printLevelOrder(int arr[], int size) {
    int i = 0, j = 0;
    while (j < size) {
        // 打印当前层的所有元素
        for (i = j; i < 2 * j + 1 && i < size; ++i) {
            printf("%d ", arr[i]);
        }
        j = j + 1;
        printf("\n");
    }
}

// 使用上述函数打印完全二叉树的层序遍历
printLevelOrder(completeBinaryTree, size);
3.2 满二叉树(Full Binary Tree)

满二叉树中,除了叶子节点外,每个节点都有两个子节点。

代码案例

由于满二叉树的特性,它可以用指针链接的方式来表示:

// 创建一个满二叉树节点
BinaryTreeNode* createFullBinaryTreeNode(int data) {
    BinaryTreeNode* node = createBinaryTreeNode(data);
    // 为每个节点创建两个子节点
    node->left = createBinaryTreeNode(2 * data);
    node->right = createBinaryTreeNode(2 * data + 1);
    return node;
}
3.3 二叉搜索树(Binary Search Tree)

二叉搜索树是一种特殊的二叉树,其中每个节点的值都大于其左子树中的任何节点的值,并且小于其右子树中的任何节点的值。

代码案例

以下是BST的插入操作的代码示例:

// BST插入操作
BinaryTreeNode* insertBST(BinaryTreeNode* root, int data) {
    if (root == NULL) {
        root = createBinaryTreeNode(data);
    } else if (data < root->data) {
        root->left = insertBST(root->left, data);
    } else {
        root->right = insertBST(root->right, data);
    }
    return root;
}
3.4 平衡二叉树(Balanced Binary Tree)

平衡二叉树通过保持树的高度尽可能低,确保左右子树的高度差不超过1,从而保证操作的效率。

代码案例

平衡二叉树通常需要复杂的旋转操作来维护平衡,以下是AVL树(一种平衡二叉树)的一个简单插入示例:

// AVL树节点定义,增加平衡因子(高度差)
typedef struct AVLNode {
    int data;
    int height;
    AVLNode* left;
    AVLNode* right;
} AVLNode;

// 计算节点的平衡因子
int getBalance(AVLNode* node) {
    if (node == NULL)
        return 0;
    return getHeight(node->left) - getHeight(node->right);
}

// AVL树的插入操作(简化版,不包括旋转)
AVLNode* insertAVL(AVLNode* root, int data) {
    if (root == NULL)
        return createAVLNode(data); // createAVLNode是创建节点的辅助函数
    if (data < root->data)
        root->left = insertAVL(root->left, data);
    else if (data > root->data)
        root->right = insertAVL(root->right, data);
    else
        return root;

    // 更新高度
    root->height = 1 + max(getHeight(root->left), getHeight(root->right));

    // 获取平衡因子并进行相应的旋转操作(代码略)

    return root;
}

 

3.5 红黑树(Red-Black Tree) 

红黑树是一种自平衡的二叉搜索树,通过节点颜色的约束来保持平衡。

代码案例

红黑树的实现相对复杂,涉及到多种情况的旋转和颜色调整。以下是创建红黑树节点的基本结构:

 

// 红黑树节点定义
typedef enum { RED, BLACK } Color;

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

// 创建红黑树节点
RBNode* createRBNode(int data) {
    RBNode* node = (RBNode*)malloc(sizeof(RBNode));
    node->data = data;
    node->color = RED; // 新节点通常为红色
    node->left = NULL;
    node->right = NULL;
    node->parent = NULL;
    return node;
}
3.6 线索二叉树(Threaded Binary Tree)

线索二叉树通过将空的子节点指针“线索化”以指向其他有意义的节点,从而优化了遍历操作。

代码案例

以下是线索二叉树的创建和线索化过程:

// 线索化二叉树节点
typedef struct ThreadedBinaryTreeNode {
    int data;
    struct ThreadedBinaryTreeNode *left, *right;
    int ltag, rtag; // 标记线索
} TBTNode;

// 创建线索化节点
void createThreadedNode(TBTNode** node, int data) {
    *node = (TBTNode*)malloc(sizeof(TBTNode));
    (*node)->data = data;
    (*node)->left = NULL;
    (*node)->right = NULL;
    (*node)->ltag = 0;
    (*node)->rtag = 0;
}

// 线索化右子树为空的节点
void threadRight(TBTNode* node) {
    if (node->right == NULL) {
        node->right = node->left;
        node->rtag = 1;
    }
}

// 遍历线索二叉树(in-order)
void inOrderThreadedTraversal(TBTNode* node) {
    while (node->ltag == 0) {
        node = node->left;
    }
    while (1) {
        printf("%d ", node->data);
        if (node->rtag == 1) {
            node = node->right;
            while (node->ltag == 0) {
                node = node->left;
            }
        } else {
            if (node->right != NULL) {
                threadRight(node);
            }
            node = node->right;
        }
        if (node == NULL) break;
    }
}

结语

本文详细介绍了树和二叉树的基本概念、结构特点以及C语言实现。此外,还探讨了一些高级二叉树概念,如完全二叉树、二叉搜索树、平衡二叉树等,并通过代码示例展示了它们的实现。理解这些基础概念和高级特性对于掌握数据结构至关重要。希望读者能够通过本文加深对树和二叉树的理解,并在未来的学习或工作中灵活运用它们。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值