C语言二叉树常见操作详解【前序,中序,后序,层次遍历及非递归查找,统计个数,比较,求深度】

C语言二叉树常见操作详解

什么是二叉树

二叉树是一种重要的数据结构,它由节点组成,每个节点最多有两个子节点,左子节点和右子节点。

二叉树具有以下性质:

  1. 每个节点最多有两个子节点。
  2. 左子节点的值小于父节点的值。
  3. 右子节点的值大于父节点的值。
  4. 左右子树都是二叉树。

二叉树的基本操作

1.创建一个二叉树

使用递归的方式来创建一个二叉树,每次创建节点时,递归创建左右子树。以下是一个示例代码:

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

TreeNode* createBinaryTree(){
    int data;
    scanf("%d", &data);
    if(data == -1) {
        return NULL;
    }
    TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));
    root->data = data;
    root->left = createBinaryTree();
    root->right = createBinaryTree();
    return root;
}

使用外部数据输入的方式来创建二叉树,当输入 -1 时,代表该节点为空。

2.前序遍历二叉树

前序遍历的顺序是:先访问根节点,再遍历左子树和右子树。以下是一个示例代码:

void preOrderTraverse(TreeNode* root){
    if(root!=NULL) {
        printf("%d ",root->data);
        preOrderTraverse(root->left);
        preOrderTraverse(root->right);
    }
}

例如,对于下图所示的二叉树:

     1
   /   \
  2     3
 / \   / \
4   5  6  7

它的前序遍历结果为: 1 2 4 5 3 6 7

3.中序遍历二叉树

中序遍历的顺序是:先遍历左子树,再访问根节点,最后遍历右子树。以下是一个示例代码:

void inOrderTraverse(TreeNode* root){
    if(root!=NULL) {
        inOrderTraverse(root->left);
        printf("%d ",root->data);
        inOrderTraverse(root->right);
    }
}

例如,对于下图所示的二叉树:

     1
   /   \
  2     3
 / \   / \
4   5  6  7

它的中序遍历结果为: 4 2 5 1 6 3 7

4.后序遍历二叉树

后序遍历的顺序是:先遍历左子树,再遍历右子树,最后访问根节点。以下是一个示例代码:

void postOrderTraverse(TreeNode* root){
    if(root!=NULL) {
        postOrderTraverse(root->left);
        postOrderTraverse(root->right);
        printf("%d ",root->data);
    }
}

例如,对于下图所示的二叉树:

     1
   /   \
  2     3
 / \   / \
4   5  6  7

它的后序遍历结果为: 4 5 2 6 7 3 1

5.层次遍历二叉树

层次遍历的顺序是:按照从上往下、从左往右的方式,逐层遍历每一个节点。以下是一个示例代码:

void levelOrderTraverse(TreeNode* root){
    if(root == NULL){
        return;
    }
    Queue q;
    initQueue(&q);
    enqueue(&q, root);
    while(!isEmpty(&q)){
        TreeNode* node = dequeue(&q);
        printf("%d ", node->data);
        if(node->left != NULL) enqueue(&q, node->left);
        if(node->right != NULL) enqueue(&q, node->right);
    }
}

其中,使用队列来存储每一层的节点队列,先将根节点入队,之后每次出队一个节点并输出,再将该节点的左右子节点入队。

例如,对于下图所示的二叉树:

     1
   /   \
  2     3
 / \   / \
4   5  6  7

它的层次遍历结果为: 1 2 3 4 5 6 7

6.非递归查找

使用非递归的方式,从根节点开始查找二叉树中是否存在某个节点。以下是一个示例代码:

TreeNode* find(TreeNode* root, int val){
    if(root == NULL) return NULL;
    Stack s;
    initStack(&s);
    push(&s, root);
    while(!isEmptyStack(&s)){
        TreeNode* node = top(&s); pop(&s);
        if(node->data == val) return node;
        if(node->right != NULL) push(&s, node->right);
        if(node->left != NULL) push(&s, node->left);
    }
    return NULL;
}

其中,使用栈来存储每一个节点,先将根节点入栈,之后每次取出一个节点并比较,如果相等则返回该节点,否则将其右子节点和左子节点入栈。

7.统计节点个数

统计二叉树中节点的个数,包括根节点和左右子树中的所有节点。以下是一个示例代码:

int count(TreeNode* root){
    if(root == NULL) return 0;
    return count(root->left) + count(root->right) + 1;
}

其中,使用递归的方式遍历每一个节点,并计数。

8.二叉树比较

比较两个二叉树是否相同,相同返回 true,否则返回 false。以下是一个示例代码:

bool isEqual(TreeNode* root1, TreeNode* root2){
    if(root1 == NULL && root2 == NULL) return true;
    if(root1 == NULL || root2 == NULL) return false;
    if(root1->data != root2->data) return false;
    return isEqual(root1->left, root2->left) && isEqual(root1->right, root2->right);
}

其中,使用递归的方式分别比较两个二叉树的根节点、左子树和右子树。

9.求二叉树深度

求二叉树的深度,即二叉树的最大深度。以下是一个示例代码:

int maxDepth(TreeNode* root){
    if(root == NULL) return 0;
    int left = maxDepth(root->left);
    int right = maxDepth(root->right);
    return left > right ? left + 1 : right + 1;
}

其中,使用递归的方式分别求左子树和右子树的深度,并加上根节点的深度 1,最后返回较大值。

示例说明

示例一

我们输入以下数据:

1
2
4
-1
-1
5
-1
-1
3
6
-1
-1
7
-1
-1

使用示例代码中的 createBinaryTree() 方法,得到以下的二叉树:

     1
   /   \
  2     3
 / \   / \
4   5  6  7

使用示例代码中的各种遍历、查找、比较、求深度等方法可以对该二叉树进行各种操作。

示例二

我们输入以下数据:

1
-1
2
-1
3
-1

使用示例代码中的 createBinaryTree() 方法,得到以下的二叉树:

  1
   \
    2
     \
      3

使用示例代码中的各种遍历、查找、比较、求深度等方法可以对该二叉树进行各种操作,例如:

  • 中序遍历结果: 1 2 3
  • 非递归查找 4,结果为 NULL
  • 统计节点个数为 3
  • 求深度为 3

总结

二叉树是一种常用的数据结构,常用的操作包括创建、遍历、查找、比较和求深度等。掌握这些基本操作后,可根据实际需求进行扩展。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言二叉树常见操作详解【前序,中序,后序,层次遍历及非递归查找,统计个数,比较,求深度】 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • vue-simple-uploader上传插件

    当然,我很乐意为您提供Vue-Simple-Uploader上传插件的完整攻略。以下是详细的步骤和示例: 步骤1:了解Vue-Simple-Uploader上传插件 Vue-Simple-Uploader是一个基于Vue.js的上传插件,可以用于上传文件和图片。插件有简单易用的界面和丰富的功能,可以满足不同用户的需求。 步骤2:安装Vue-Simple-Up…

    other 2023年5月6日
    00
  • iOS自定义身份证键盘

    iOS自定义身份证键盘是一种应用场景非常广泛的自定义键盘,在中国的银行、保险、政府等机构中都有应用。在这里,我将为大家介绍如何实现一个完整的iOS自定义身份证键盘。 第一步:创建一个新的自定义键盘 首先,我们需要在Xcode中创建一个新的CustomKeyboard项目。选择 File -> New -> Target -> Applica…

    other 2023年6月25日
    00
  • 以win7为例谈NTFS的高级特性和应用

    以win7为例谈NTFS的高级特性和应用 一、NTFS的概述 NTFS是一种新型的文件系统,它是Windows系统中默认的文件系统,自Windows NT操作系统开始就被使用,目前已成为Windows家族操作系统里最为普遍的文件系统。NTFS在大多数情况下比FAT文件系统更具有优势: 支持更大的文件和分区,允许单个文件大小为16EB(对所有现代硬件都远远超出…

    other 2023年6月27日
    00
  • 跟我学习javascript的作用域与作用域链

    学习JavaScript的作用域与作用域链攻略 1. 什么是作用域? 作用域是指在程序中定义变量的区域,它决定了变量的可见性和生命周期。在JavaScript中,作用域可以分为全局作用域和局部作用域。 全局作用域:在整个程序中都可以访问的变量被称为全局变量,它们在程序开始执行时创建,在程序结束时销毁。 局部作用域:在函数内部定义的变量被称为局部变量,它们只能…

    other 2023年8月19日
    00
  • Windows 批处理cmd/bat常用命令详解

    Windows 批处理cmd/bat常用命令详解 前言 Windows 批处理(cmd/bat)是一种可以在 Windows 系统下执行的脚本语言,可以用于自动化任务、批量处理等场景。本文将介绍一些常用的批处理命令。 常用命令 echo echo 命令用于在控制台输出文本或变量,并且可以通过重定向符号将输出结果写入文件。示例如下: @echo off ech…

    other 2023年6月26日
    00
  • Git客户端TortoiseGit(Windows系统)的使用方法

    Git客户端TortoiseGit(Windows系统)的使用方法 简介 TortoiseGit是一个Windows操作系统上的Git客户端工具。它提供了方便易用的Git图形化界面,为Git的使用带来了便利。 安装 前往TortoiseGit官网下载最新版本的安装包。 运行安装程序,按照提示进行安装即可。 配置 在使用TortoiseGit前,需要进行一些配…

    other 2023年6月25日
    00
  • 9个顶级开发iot项目的开源物联网平台

    9个顶级开发IoT项目的开源物联网平台 在现代工业和农业中,物联网(IoT)技术已经被广泛使用。为了实现更智能、可靠和高效的物联网解决方案,需要一个强大的物联网平台。在本文中,我们将介绍9个顶级的开源物联网平台,这些平台可以帮助开发人员快速搭建物联网系统,从而实现更好的智能化管理和控制。 1. Eclipse IoTS Wapama Eclipse IoTS…

    其他 2023年3月29日
    00
  • Angular.js中控制器之间的传值详解

    Angular.js中控制器之间的传值详解 在Angular.js中,控制器之间的传值是非常常见和重要的操作。下面将详细讲解如何在Angular.js中实现控制器之间的传值,并提供两个示例说明。 1. 使用服务(Service)进行传值 Angular.js中的服务是一个可被多个控制器共享的对象。通过在服务中定义变量或方法,我们可以在不同的控制器之间传递数据…

    other 2023年8月20日
    00
合作推广
合作推广
分享本页
返回顶部