首页 > 其他分享 >二叉树小结

二叉树小结

时间:2024-06-09 10:30:53浏览次数:18  
标签:遍历 小结 二叉树 heap array root 节点

目录

简介

二叉树的种类

在实际开发中

评估二叉树的性能

搜索二叉树代码实现

二叉树堆的实现

红黑树简介


简介

二叉树是一种特殊的树,每个节点最多有两个子节点,通常被称为左子节点和右子节点。它是计算机科学中的一种基础且重要的树形结构,被广泛应用在各种算法和数据结构中。二叉树的特性包括递归性(左子树和右子树本身就是二叉树)和有序性(左子树和右子树的节点不能随意颠倒)。

二叉树的遍历方式有三种,分别为前序遍历、中序遍历和后序遍历。前序遍历是先访问根节点,然后递归遍历左子树,最后递归遍历右子树;中序遍历是先递归遍历左子树,然后访问根节点,最后递归遍历右子树;后序遍历是先递归遍历左子树,然后递归遍历右子树,最后访问根节点。

二叉树的应用非常广泛,例如在Linux和Windows的目录结构中就有二叉树的身影。在LeetCode平台上,很多题目也涉及到二叉树的遍历和操作,如第101题"对称二叉树"、第124题"二叉树中的最大路径和"等。在实际应用中,二叉树的各种算法和操作知识也是程序员必备的技能。

二叉树的种类

二叉树有很多种类,不同的种类有不同的特点和应用场景。以下是一些常见的二叉树类型:

  1. 满二叉树:每一层的节点数都达到最大值,所有节点总数为2^h - 1,其中h为树的高度。满二叉树经常被用来作为快速查找的树形数据结构。

  2. 完全二叉树:若设二叉树的高度为h,除第h层外,其它层的节点数都达到了最大值,第h层的节点尽量集中在左侧,这种二叉树称为完全二叉树。完全二叉树是满二叉树的特例。

  3. 平衡二叉树:它的左右子树的节点数大致相等,使得树的高度h尽可能小。常见的平衡二叉树有AVL树和红黑树。

  4. 二叉搜索树:也称为排序二叉树或搜索二叉树,它的特点是左子树上所有节点的值均小于或等于根节点的值,右子树上所有节点的值均大于根节点的值。

  5. 线索二叉树:在普通二叉树的基础上,添加线索,使得每个节点的前驱和后继都能快速找到。线索二叉树经常被用在需要高效遍历和查找的场景中。

  6. :是一种特殊的完全二叉树,用于实现排序和解决Top-k问题,它可以看作是二叉树的扩展。

这些种类并非互相排斥,而是可以组合和衍生出更多的二叉树类型。例如,线索二叉树就是完全二叉树加上线索的结构,而平衡二叉树则是在保证完全二叉树的基础上,通过调整节点让其更平衡。

在实际开发中

选择合适的二叉树类型通常取决于具体的需求、性能要求和实现复杂度。以下是一些考虑因素:

  1. 数据特性:如果数据集已经是有序的或者近似有序,可以使用二叉搜索树,如AVL树或红黑树,因为它们可以在对数时间复杂度内完成查找、插入和删除操作。

  2. 性能要求:如果需要高性能的搜索和排序操作,可以选择平衡二叉树,如AVL树或红黑树,因为它们能够保持树的平衡,从而保证操作的时间复杂度。

  3. 内存使用:如果内存使用是一个关键因素,可以考虑使用满二叉树,因为它在相同节点数的情况下具有最小的内存占用。

  4. 动态修改:如果树结构需要频繁地插入和删除节点,平衡二叉树是更好的选择,因为它们能够自我平衡以保持高效的操作性能。

  5. 遍历需求:如果需要频繁地进行前序、中序或后序遍历,二叉搜索树是一个好选择,因为这些操作在二叉搜索树中是自然且高效的。

  6. 扩展性和兼容性:如果树结构需要扩展或者需要与其他数据结构兼容,选择具有良好接口和扩展性的树结构,如自定义的二叉树或者堆。

  7. 线索化:如果需要对已遍历的节点进行操作,如修改节点值,线索二叉树可以提供更多的便利,因为它允许双向访问节点。

  8. 特定应用:某些特定的应用可能需要特定的二叉树结构,例如Trie树用于字符串搜索,堆用于优先队列等。

在实际开发中,可能需要根据具体情况进行权衡,选择最适合当前场景的二叉树类型。例如,如果一个应用需要频繁的插入和删除操作,并且对内存使用有严格的要求,那么可能会选择一种平衡二叉树,如红黑树,因为它在保证平衡的同时,也尽量减少了内存的消耗。

评估二叉树的性能

  1. 时间复杂度

    • 查找:在二叉搜索树中,查找操作的时间复杂度通常是O(log n),其中n是树中节点的数量。
    • 插入和删除:在平衡二叉树(如AVL树或红黑树)中,插入和删除操作的时间复杂度也是O(log n)。
    • 遍历:前序、中序和后序遍历的时间复杂度都是O(n),因为每个节点都会被访问一次。
  2. 空间复杂度

    • 空间复杂度主要取决于树的结构和实现。对于普通的二叉树,空间复杂度是O(n),因为需要存储每个节点。
    • 对于平衡二叉树,空间复杂度可能略高于O(n),因为需要额外的空间来维护树的平衡。
  3. 平衡性

    • 平衡二叉树(如AVL树或红黑树)能够保持树的平衡,这有助于维持操作的效率。
    • 非平衡二叉树(如普通二叉搜索树)在插入和删除操作后可能变得不平衡,导致性能下降。
  4. 内存使用

    • 满二叉树由于每一层都是满的,因此相比其他二叉树类型,它具有更少的内存占用。
    • 平衡二叉树虽然内存使用稍多,但提供了更好的性能保证。
  5. 可扩展性

    • 一些二叉树结构(如堆)具有良好的可扩展性,可以很容易地扩展到更高级的功能。
    • 其他类型的二叉树可能需要更多的定制工作来实现特定的需求。
  6. 实现复杂度

    • 一些二叉树结构(如线索二叉树)在实现上可能更加复杂,但提供了额外的功能,如双向遍历。
    • 简单的二叉树结构(如普通二叉搜索树)实现起来相对简单,但可能需要更多的维护来保持性能。
  7. 特定操作的效率

    • 一些二叉树结构可能在特定的操作上更加高效,例如,二叉搜索树在查找操作上非常高效,而堆在解决Top-k问题上非常有效。

在评估二叉树的性能时,应该根据具体的应用场景和需求来进行选择。在实际应用中,可能需要根据性能测试结果和实际运行情况进行调整和优化。

搜索二叉树代码实现

在C语言中实现一个基本的二叉树结构,我们可以定义一个节点结构体,并且实现基本的插入、删除和遍历等功能。以下是一个简单的实现示例:

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

typedef struct TreeNode {
    int value;
    struct TreeNode *left;
    struct TreeNode *right;
} TreeNode;

// 创建一个新节点
TreeNode* createNode(int value) {
    TreeNode* newNode = (TreeNode*) malloc(sizeof(TreeNode));
    if (!newNode) {
        printf("Memory allocation failed\n");
        exit(1);
    }
    newNode->value = value;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

// 插入节点
TreeNode* insertNode(TreeNode* root, int value) {
    if (root == NULL) {
        return createNode(value);
    }

    if (value < root->value) {
        root->left = insertNode(root->left, value);
    } else if (value > root->value) {
        root->right = insertNode(root->right, value);
    }

    return root;
}

// 中序遍历
void inorderTraversal(TreeNode* root) {
    if (root != NULL) {
        inorderTraversal(root->left);
        printf("%d ", root->value);
        inorderTraversal(root->right);
    }
}

// 销毁二叉树
void destroyTree(TreeNode* root) {
    if (root != NULL) {
        destroyTree(root->left);
        destroyTree(root->right);
        free(root);
    }
}

int main() {
    TreeNode* root = NULL;

    root = insertNode(root, 50);
    root = insertNode(root, 30);
    root = insertNode(root, 70);
    root = insertNode(root, 20);
    root = insertNode(root, 40);
    root = insertNode(root, 60);
    root = insertNode(root, 80);

    printf("Inorder traversal of the given tree:\n");
    inorderTraversal(root);
    printf("\n");

    destroyTree(root);
    return 0;
}

这个示例中,我们定义了一个简单的二叉搜索树。节点包含一个整数值,以及指向左右子节点的指针。我们提供了插入节点、中序遍历和销毁树的功能。

注意,这是一个非常基础的实现,没有实现删除节点等更复杂的功能。在实际应用中,你可能需要根据具体需求来实现更多的功能,例如平衡树、哈希表等高级数据结构。

二叉树堆的实现

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

typedef struct MaxHeap {
    int* array; // 堆的数组表示
    int size;   // 堆的大小
    int capacity; // 堆的容量
} MaxHeap;

// 创建一个最大堆
MaxHeap* createMaxHeap(int capacity) {
    MaxHeap* heap = (MaxHeap*) malloc(sizeof(MaxHeap));
    if (!heap) {
        printf("Memory allocation failed\n");
        exit(1);
    }
    heap->array = (int*) malloc(capacity * sizeof(int));
    if (!heap->array) {
        printf("Memory allocation failed\n");
        exit(1);
    }
    heap->size = 0;
    heap->capacity = capacity;
    return heap;
}

// 堆化过程,修复违反最大堆性质的子树
void heapifyDown(MaxHeap* heap, int index) {
    int leftChild = 2 * index + 1;
    int rightChild = 2 * index + 2;
    int largest = index;

    if (leftChild < heap->size && heap->array[leftChild] > heap->array[largest]) {
        largest = leftChild;
    }

    if (rightChild < heap->size && heap->array[rightChild] > heap->array[largest]) {
        largest = rightChild;
    }

    if (largest != index) {
        int temp = heap->array[largest];
        heap->array[largest] = heap->array[index];
        heap->array[index] = temp;

        heapifyDown(heap, largest);
    }
}

// 堆化过程,修复违反最大堆性质的父节点
void heapifyUp(MaxHeap* heap, int index) {
    while (index > 0 && heap->array[(index - 1) / 2] < heap->array[index]) {
        int temp = heap->array[(index - 1) / 2];
        heap->array[(index - 1) / 2] = heap->array[index];
        heap->array[index] = temp;

        index = (index - 1) / 2;
    }
}

// 插入元素
void insertMaxHeap(MaxHeap* heap, int key) {
    if (heap->size == heap->capacity) {
        printf("Heap is full\n");
        return;
    }

    heap->array[heap->size] = key;
    heapifyUp(heap, heap->size);
    heap->size++;
}

// 提取堆顶元素
int extractMax(MaxHeap* heap) {
    if (heap->size == 0) {
        printf("Heap is empty\n");
        return INT_MIN;
    }

    int root = heap->array[0];
    heap->array[0] = heap->array[heap->size - 1];
    heap->size--;
    heapifyDown(heap, 0);

    return root;
}

// 销毁堆
void destroyHeap(MaxHeap* heap) {
    free(heap->array);
    free(heap);
}

int main() {
    MaxHeap* heap = createMaxHeap(10);

    insertMaxHeap(heap, 45);
    insertMaxHeap(heap, 20);
    insertMaxHeap(heap, 14);
    insertMaxHeap(heap, 12);
    insertMaxHeap(heap, 31);
    insertMaxHeap(heap, 7);
    insertMaxHeap(heap, 11);
    insertMaxHeap(heap, 13);
    insertMaxHeap(he

红黑树简介

红黑树(Red-Black Tree)是一种自平衡的二叉搜索树,其中每个节点都有一个颜色属性,要么是红色,要么是黑色。红黑树通过颜色和一系列性质来保证树的平衡性。

以下是红黑树的基本性质:

1每个节点要么是红色,要么是黑色。
2根节点是黑色的。
3所有叶子节点(NIL节点,空节点)是黑色的。
4如果一个节点是红色的,则它的两个子节点都是黑色的。
5对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数目的黑色节点。

标签:遍历,小结,二叉树,heap,array,root,节点
From: https://blog.csdn.net/2401_83427936/article/details/139558521

相关文章

  • 【力扣】二叉树的最大深度
    给定一个二叉树root,返回其最大深度。二叉树的最大深度是指从根节点到最远叶子节点的最长路径上的节点数。示例1:输入:root=[3,9,20,null,null,15,7]输出:3示例2:输入:root=[1,null,2]输出:2层序遍历求深度流程层序遍历是对二叉树每一层进行遍历,我们定义一个......
  • 【力扣】对称二叉树
    给你一个二叉树的根节点root,检查它是否轴对称。示例1:输入:root=[1,2,2,3,4,4,3]输出:true示例2:输入:root=[1,2,2,null,3,null,3]输出:false队列层序遍历流程进行两次同步遍历,分别从根节点的左子树和右子树开始,然后比较每个节点的值代码实现classSolution......
  • 【力扣】翻转二叉树
    给你一棵二叉树的根节点root,翻转这棵二叉树,并返回其根节点。示例1:输入:root=[4,2,7,1,3,6,9]输出:[4,7,2,9,6,3,1]示例2:输入:root=[2,1,3]输出:[2,3,1]示例3:输入:root=[]输出:[]递归法流程把每一个节点的左右孩子互换,就实现了整体翻转的效果。使用递归......
  • 【第四节】C/C++数据结构之树与二叉树
    目录一、基本概念与术语二、树的ADT三、二叉树的定义和术语四、平衡二叉树4.1解释4.2相关经典操作4.3代码展示一、基本概念与术语树(Tree)是由一个或多个结点组成的有限集合T。其中:1有一个特定的结点,称为该树的根(root)结点;2每个树都有且仅有一个特定的,称为......
  • 二叉树-数据结构
    父节点地址值左子节点地址右子节点地址每一个节点往下面,都是会分成左右两个树的结点度,就是子节点的数量二叉树就是生活中的树的概念树的高度是以最大的数量去数小的往左边放,大的往右边放以根节点为坐标,小于根节点的储存在左边,大的根节点放在右边和根节点相等的数,我们......
  • Day17| 110.平衡二叉树、 257. 二叉树的所有路径 、 404.左叶子之和
    110.平衡二叉树(优先掌握递归)再一次涉及到,什么是高度,什么是深度,可以巩固一下。题目链接/文章讲解/视频讲解:https://programmercarl.com/0110.平衡二叉树.html#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):......
  • 144. 二叉树的前序遍历
    /***Definitionforabinarytreenode.*typeTreeNodestruct{*Valint*Left*TreeNode*Right*TreeNode*}*/funcpreorderTraversal(root*TreeNode)[]int{returnpre2(root)//vals:=[]int{}//pre1(root,&val......
  • Day16 | 104.二叉树的最大深度 、111.二叉树的最小深度 、222.完全二叉树的节点个数
    104.二叉树的最大深度(优先掌握递归)什么是深度,什么是高度,如何求深度,如何求高度,这里有关系到二叉树的遍历方式。大家要先看视频讲解,就知道以上我说的内容了,很多录友刷过这道题,但理解的还不够。题目链接/文章讲解/视频讲解:https://programmercarl.com/0104.二叉树的最大深度.ht......
  • 二叉链表---二叉树的简单实现
    实验内容将二叉链表视为森林的孩子兄弟链表,计算森林中叶子个数。代码实现#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>#include<stdlib.h>#include<string.h>#defineElemTypeinttypedefstructBtree{ ElemTypeelem; structBtree*lchild,*rchild......
  • Python3 元组、列表、字典、集合小结
    前言本文主要对Python中的元组、列表、字典、集合进行小结,主要内容包括知识点回顾、异同点、使用场景。文章目录前言一、知识点回顾1、列表(List)2、元组(Tuple)3、字典(Dictionary)4.、集合(Set)二、异同点1、异构性2、可变性3、有序性4、可迭代性三、使用场景1、列表(List......