【二叉树教程详解以及C语言/C++实现二叉树】

news/2025/3/14 1:52:51/

二叉树

二叉树是一种特殊的树状数据结构,其中每个节点最多有两个子节点。一个节点称为父节点,两个子节点分别称为左子节点和右子节点。

一、什么是二叉树

二叉树是一种特殊的树状数据结构,其中每个节点最多有两个子节点。每个节点包含一个数据元素和指向其左子节点和右子节点的指针。左子节点的值小于或等于父节点的值,而右子节点的值大于父节点的值。这个特性使得二叉树在查找、插入和删除操作方面非常高效。

     A/ \B   C/ \   \D   E   F

二叉树通常用于模拟具有层级结构的数据。它的一些常见应用包括搜索算法(例如二叉搜索树)、表达式树、哈夫曼编码树等。在二叉树中,我们可以使用不同的遍历方式来访问节点,包括先序遍历、中序遍历和后序遍历

二、二叉树遍历方式

1、先序遍历

从根节点开始,先访问根节点,然后递归地对左子树和右子树进行先序遍历。这种遍历方式可以用于复制整个树的结构。

假设我们有如下一棵二叉树:

     1/ \2   3/ \   \4   5   6

首先,我们访问根节点 1,然后遍历左子树。左子树的根节点是 2,我们继续访问它,然后遍历它的左子树。左子树的根节点是 4,我们继续访问它,然后发现它没有左子树和右子树了,所以我们返回到节点 2,然后遍历它的右子树。

右子树的根节点是 5,我们继续访问它,然后发现它没有左子树和右子树了,所以我们返回到节点 2,然后返回到根节点 1,然后遍历根节点的右子树。

右子树的根节点是 3,我们继续访问它,然后遍历它的左子树。左子树是空的,所以我们返回到节点 3,然后遍历它的右子树。

右子树的根节点是 6,我们继续访问它,然后发现它没有左子树和右子树了,所以我们返回到节点 3,然后返回到根节点 1,遍历结束。

最终的先序遍历结果是:1 2 4 5 3 6

下面是先序遍历的具体步骤图解:

     1/ \2   3/ \   \4   5   6
  1. 访问根节点 1
  2. 遍历左子树
    • 访问根节点 2
    • 遍历左子树
      • 访问根节点 4
      • 左子树为空,返回
    • 遍历右子树
      • 访问根节点 5
      • 左子树为空,返回
  3. 遍历右子树
    • 访问根节点 3
    • 遍历左子树(为空,返回)
    • 遍历右子树
      • 访问根节点 6
      • 左子树为空,返回
最终的先序遍历结果是:1 2 4 5 3 6

2、中序遍历

中序遍历是二叉树遍历的一种方式,其遍历顺序为:从根节点开始,先递归地对左子树进行中序遍历,然后访问根节点,最后递归地对右子树进行中序遍历。对于二叉搜索树,中序遍历可以实现升序输出。

下面是一个二叉树的示例:

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

中序遍历的过程可以使用递归或者栈来实现。下面详细介绍一下两种方法。

(1)递归法

递归法是最简单的实现方式。具体步骤如下:

  1. 如果当前节点为空,则返回。
  2. 递归遍历当前节点的左子树。
  3. 访问当前节点。
  4. 递归遍历当前节点的右子树。

下面是用递归法实现中序遍历的示例代码:

#include <stdio.h>
#include <stdlib.h>struct Node {int val;struct Node* left;struct Node* right;
};void inorderTraversal(struct Node* root) {if (root == NULL) {return;}inorderTraversal(root->left);printf("%d ", root->val);inorderTraversal(root->right);
}

(2)栈法

栈法使用一个栈来辅助遍历过程。具体步骤如下:

  1. 初始化一个空栈和一个指针,指向根节点。
  2. 当栈不为空或者指针不为空时,执行以下操作:
    • 如果指针不为空,将指针压入栈,并将指针指向其左子树。
    • 如果指针为空,弹出栈顶元素并访问,然后将指针指向其右子树。
  3. 当栈为空且指针为空时,遍历结束。

下面是用栈法实现中序遍历的示例代码:

#include <stdio.h>
#include <stdlib.h>struct Node {int val;struct Node* left;struct Node* right;
};void inorderTraversal(struct Node* root) {struct Node* stack[1000];int top = -1;struct Node* curr = root;while (top != -1 || curr != NULL) {if (curr != NULL) {stack[++top] = curr;curr = curr->left;} else {curr = stack[top--];printf("%d ", curr->val);curr = curr->right;}}
}

无论是递归法还是栈法,它们的时间复杂度都是O(n),其中n为二叉树的节点个数。

3、后序遍历

后序遍历(Postorder Traversal)是一种二叉树的遍历方式,它的遍历顺序是先遍历左子树,再遍历右子树,最后访问根节点。这种遍历方式常用于****内存回收析构函数调用

下面是一个示例二叉树:

      1/ \2   3/ \   \4   5   6

按照后序遍历的顺序,应该先遍历左子树,再遍历右子树,最后访问根节点。所以该二叉树的后序遍历结果为:

4 -> 5 -> 2 -> 6 -> 3 -> 1

接下来,我们使用C语言来实现二叉树的后序遍历。

首先,我们需要定义二叉树的结构,包括节点的值以及左右子节点的指针。

#include <stdio.h>
#include <stdlib.h>// 定义二叉树的结构
struct TreeNode {int val;struct TreeNode* left;struct TreeNode* right;
};

然后,我们需要创建一个新的二叉树节点的函数。

// 创建一个新的二叉树节点
struct TreeNode* createNode(int val) {struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));newNode->val = val;newNode->left = NULL;newNode->right = NULL;return newNode;
}

接下来,我们来实现二叉树的后序遍历函数。

// 后序遍历二叉树
void postorderTraversal(struct TreeNode* root) {if (root == NULL) {return;}postorderTraversal(root->left);   // 遍历左子树postorderTraversal(root->right);  // 遍历右子树printf("%d ", root->val);         // 访问根节点
}

在后序遍历函数中,我们首先判断当前节点是否为空,如果为空则返回。然后依次递归遍历左子树和右子树,最后访问根节点。

最后,我们可以在主函数中创建一个示例二叉树,并调用后序遍历函数来进行遍历。

int main() {// 创建示例二叉树struct TreeNode* root = createNode(1);root->left = createNode(2);root->right = createNode(3);root->left->left = createNode(4);root->left->right = createNode(5);root->right->right = createNode(6);// 后序遍历二叉树printf("后序遍历结果:");postorderTraversal(root);printf("\n");return 0;
}

运行上述代码,输出结果为:

后序遍历结果:4 5 2 6 3 1

三、二叉树特性

除了遍历方式,二叉树还有一些其他的特性:

  • 完全二叉树:在完全二叉树中,除了最后一层,其他每一层的节点都被填满,且最后一层的节点从左到右依次填入。这种树结构在数组中可以高效地存储。
  • 满二叉树:满二叉树是一种所有节点都具有0个或2个子节点的二叉树。在满二叉树中,所有的叶子节点都在同一层。
  • 平衡二叉树:在平衡二叉树中,任何节点的左子树和右子树的高度差最多为1。这样可以保持树的平衡,提高搜索、插入和删除操作的效率。
  • 二叉搜索树:二叉搜索树(BST)是一种具有以下特性的二叉树:对于任意节点,其左子树中的所有节点的值都小于它,而右子树中的所有节点的值都大于它。这个特性使得在二叉搜索树中进行搜索、插入和删除操作非常高效。

总而言之,二叉树是一种重要的数据结构,具有广泛的应用。它的节点最多可以有两个子节点,并且可以使用不同的遍历方式来访问和处理节点。

四、二叉树实现

1、定义结构体

首先,我们定义一个结构体,表示二叉树的节点。每个节点由数据部分和两个指针部分组成,分别指向左子节点和右子节点。

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

2、创建新节点

接下来,我们实现了一个用于创建新节点的函数createNode,负责申请内存并初始化节点的数据部分。如果内存分配失败,会打印错误信息并终止程序。

Node *createNode(int data) {Node *newNode = (Node *)malloc(sizeof(Node));if (newNode == NULL) {printf("内存分配失败!\n");exit(1);}newNode->data = data;newNode->left = NULL;newNode->right = NULL;return newNode;
}

3、插入节点

接下来,我们实现了一个插入节点的函数insertNode。该函数根据传入的数据值,将新节点插入到合适的位置。如果树为空,函数会创建新节点并将其设为根节点。否则,根据数据值的大小,递归地将节点插入到左子树或右子树中。

Node *insertNode(Node *root, int data) {if (root == NULL) {return createNode(data);} else if (data < root->data) {root->left = insertNode(root->left, data);} else if (data > root->data) {root->right = insertNode(root->right, data);}return root;
}

之后,我们实现了三种遍历方式:先序遍历、中序遍历和后序遍历。这些遍历方式分别是按照特定顺序访问二叉树中的节点。

4、先序遍历

先序遍历函数preOrder按照根节点、左子树、右子树的顺序遍历树,并打印出节点的数据值。

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

5、中序遍历

中序遍历函数inOrder按照左子树、根节点、右子树的顺序遍历树,并打印出节点的数据值。

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

6、后序遍历

后序遍历函数postOrder按照左子树、右子树、根节点的顺序遍历树,并打印出节点的数据值。

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

7、main函数

最后,在main函数中,我们创建了一个空树的根节点,并通过insertNode函数插入一些数据。然后分别调用了三种遍历函数,并打印出遍历结果。

int main() {Node *root = NULL;root = insertNode(root, 50);insertNode(root, 30);insertNode(root, 20);insertNode(root, 40);insertNode(root, 70);insertNode(root, 60);insertNode(root, 80);printf("先序遍历结果:");preOrder(root);printf("\n中序遍历结果:");inOrder(root);printf("\n后序遍历结果:");postOrder(root);return 0;
}

这就是一个简单的二叉树实现的详细代码,希望这可以帮助你更好地理解二叉树的工作原理和实现方式。

五、完整代码

#include <stdio.h>
#include <stdlib.h>// 节点结构
typedef struct Node {int data;struct Node *left;struct Node *right;
} Node;// 创建一个新节点
Node *createNode(int data) {Node *newNode = (Node *)malloc(sizeof(Node));if (newNode == NULL) {printf("内存分配失败!\n");exit(1);}newNode->data = data;newNode->left = NULL;newNode->right = NULL;return newNode;
}// 插入节点
Node *insertNode(Node *root, int data) {if (root == NULL) {return createNode(data);} else if (data < root->data) {root->left = insertNode(root->left, data);} else if (data > root->data) {root->right = insertNode(root->right, data);}return root;
}// 先序遍历
void preOrder(Node *root) {if (root != NULL) {printf("%d ", root->data);preOrder(root->left);preOrder(root->right);}
}// 中序遍历
void inOrder(Node *root) {if (root != NULL) {inOrder(root->left);printf("%d ", root->data);inOrder(root->right);}
}// 后序遍历
void postOrder(Node *root) {if (root != NULL) {postOrder(root->left);postOrder(root->right);printf("%d ", root->data);}
}int main() {Node *root = NULL;root = insertNode(root, 50);insertNode(root, 30);insertNode(root, 20);insertNode(root, 40);insertNode(root, 70);insertNode(root, 60);insertNode(root, 80);printf("先序遍历结果:");preOrder(root);printf("\n中序遍历结果:");inOrder(root);printf("\n后序遍历结果:");postOrder(root);return 0;
}

http://www.ppmy.cn/news/655870.html

相关文章

微信红包API接口(PHP)

根据微信高级红包接口&#xff0c;开发PHP版本的API接口&#xff0c;现在进行主要代码分析。 红包接口调用请求代码&#xff0c;所有请求参数为必填参数与文档对应&#xff1a; class Wxapi {private $app_id wxXXXXXXXXXXXX; //公众账号appid&#xff0c;首先申请与之配套的公…

浅析微信支付:商户平台开通现金红包、指定用户发放、红包记录查询

本文是【浅析微信支付】系列文章的第十三篇&#xff0c;主要讲解在如何开通商户平台的红包功能和为用户发放红包&#xff0c;以及查询发送红包记录。 浅析微信支付系列已经更新十三篇了哟&#xff5e;&#xff0c;没有看过的朋友们可以看一下哦。 浅析微信支付&#xff1a;(余…

微信公众平台发红包接口

微信公众平台发红包功能与企业付款类似&#xff0c;首先微信商户里是需要有余额的。 请求的地址是&#xff1a;https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack 官方文档&#xff1a;https://pay.weixin.qq.com/wiki/doc/api/cash_coupon.php?chapter13_5 测试…

php调用微信红包接口

红包接口调用请求代码&#xff0c;所有请求参数为必填参数与文档对应&#xff1a; class Wxapi { private $app_id wxXXXXXXXXXXXX; //公众账号appid&#xff0c;首先申请与之配套的公众账号 private $app_secret XXXXXXXXXXXXXXXXXXXXXXXX;//公众号secret&#xff0c;用户获…

微信支付现金红包接口说明及应用实例代码

本文我将详细介绍微信红包开发的接口&#xff0c;商户调用接口时&#xff0c;通过指定发送对象以及发送金额的方式发放红包&#xff0c;领取到红包后&#xff0c;用户的资金直接进入微信零钱。后面带有具体调用php实例 微信支付现金红包接口正式开放&#xff0c;只需开通微信支…

微信红包接入2-项目集成

接上一篇&#xff1a;微信红包接入1-介入前准备 参考&#xff1a; 现金红包接口&#xff1a;https://pay.weixin.qq.com/wiki/doc/api/cash_coupon.php?chapter13_5 接下来我们来说说代码集成&#xff0c;先把上一篇那个图拿过来&#xff1a; 从上图中我们实际第一步要走的就…

微信商户现金红包api php

微信开发文档&#xff1a; 现金红包&#xff1a;https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter13_5 裂变红包&#xff1a;https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter16_5 一、微信红包SDK1、请求url: 现金红包:https:/…

【微信开发】 红包接口开发

为什么80%的码农都做不了架构师&#xff1f;>>> 参考网上好几个版本的答案咯~ 分装 红包工具类 : package com.tepusoft.web.weixin.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamR…