二叉树基本概念与遍历
程序员文章站
2022-05-06 21:29:22
...
1. 二叉树概念
一棵二叉树是结点的一个有限集合。该集合或者为空,或者是由一个根节点加上两棵分别称为左子树和右子树组成。
- 满二叉树
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,
并且所有叶子节点都在同一层上。
- 完全二叉树
如果一棵具有N个结点的二叉树的结构与满二叉树的前N个结点的结构相同,称为完全二叉树。
2. 二叉树的特点
- 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。
- 二叉树的子树有左右之分,其子树的次序不能颠倒。
3. 二叉树存储结构
二叉树主要有链式存储结构和顺序存储结构两种。
3.1 顺序存储结构
对于一棵完全二叉树所有结点按照层序自顶向下,同一层自左向右顺
序编号,就得到一个节点的顺序序列。
优点:存储完全二叉树,简单省空间。
缺点:存储一般二叉树尤其单支树,存储空间利用不高。
3.2 链式存储结构
链式存储结构可分为二叉链存储与三叉连存储。
- 二叉链存储结构
struct TreeNode
{
// 节点中存储的信息,这里假设为 char
char data;
// 当前节点左孩子节点
struct BinTreeNode* lchild;
// 当前节点右孩子节点
struct BinTreeNode* rchild;
};
- 三叉连存储结构
struct TreeNode {
// 节点中存储的信息,这里假设为 char
char data;
// 双亲结点
struct TreeNode* parent;
// 当前节点左孩子节点
struct BinTreeNode* lchild;
// 当前节点右孩子节点
struct BinTreeNode* rchild;
};
4. 二叉树的表示方法
4.1 双亲表示法
即使用双亲结点作为树中各节点的纽带,节点定义如下
struct TreeNode {
// 节点中存储的信息,这里假设为 char
char data;
// 双亲结点
struct TreeNode* parent;
};
4.2 孩子表示法
使用左右孩子节点作为树中各节点的纽带,定义如下
struct TreeNode {
// 节点中存储的信息,这里假设为 char
char data;
// 左孩子节点
struct TreeNode* lchild;
// 右孩子节点
struct TreeNode* rchild;
};
4.3 双亲孩子表示法
使用双亲结点和做右孩子节点一起作为树中各节点的纽带,定义如下
struct TreeNode {
// 节点中存储的信息,这里假设为 char
char data;
// 双亲结点
struct TreeNode* parent;
// 左孩子节点
struct TreeNode* lchild;
// 右孩子节点
struct TreeNode* rchild;
};
4.4 孩子兄弟表示法
使用当前根节点的一个孩子节点和一个兄弟节点作为树中各节点的纽带,如果只有一个兄弟或只有一个孩子,另一个孩子或兄弟用 NULL 表示,定义如下
struct TreeNode {
// 节点中存储的信息,这里假设为 char
char data;
// 兄弟结点
struct TreeNode* brother;
// 孩子节点
struct TreeNode* child;
};
5. 二叉树的遍历
遵循某种次序,遍历二叉树中的所有节点,使得每个结点被访问一次,而且仅访问一次。“访问”:即对结点施行某些操作。二叉树的遍历有四种顺序。
这里我们的树节点定义为孩子表示法。
5.1 先序遍历
先访问根结点,再访问左子树,最后访问右子树。
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
typedef struct TreeNode {
// 节点中存储的信息,这里假设为 char
char data;
// 左孩子节点
struct TreeNode* lchild;
// 右孩子节点
struct TreeNode* rchild;
} TreeNode;
void TreePreOrder(TreeNode* root) {
// 空树
if(root == NULL) {
return;
}
// 访问当前节点
printf("[%c] ", root->data);
// 访问左子树
TreePreOrder(root->lchild);
// 访问右子树
TreePreOrder(root->rchild);
}
5.2 中序遍历
先访问左子树,再访问根结点,最后访问右子树。
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
typedef struct TreeNode {
// 节点中存储的信息,这里假设为 char
char data;
// 左孩子节点
struct TreeNode* lchild;
// 右孩子节点
struct TreeNode* rchild;
} TreeNode;
void TreePreOrder(TreeNode* root) {
// 空树
if(root == NULL) {
return;
}
// 访问左子树
TreePreOrder(root->lchild);
// 访问当前节点
printf("[%c] ", root->data);
// 访问右子树
TreePreOrder(root->rchild);
}
5.3 后序遍历
先访问左子树,再访问右子树,最后访问根结点。
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
typedef struct TreeNode {
// 节点中存储的信息,这里假设为 char
char data;
// 左孩子节点
struct TreeNode* lchild;
// 右孩子节点
struct TreeNode* rchild;
} TreeNode;
void TreePreOrder(TreeNode* root) {
// 空树
if(root == NULL) {
return;
}
// 访问左子树
TreePreOrder(root->lchild);
// 访问右子树
TreePreOrder(root->rchild);
// 访问当前节点
printf("[%c] ", root->data);
}