目录
一、二叉树的遍历
二叉树的遍历分为以下三种:
前序遍历:访问顺序为 根节点—->左子树—->右子树
中序遍历:访问顺序为 左子树—>根节点—->右子树
后序遍历:访问顺序为 左子树—>右子树—->根节点
接下来针对这3种遍历方式进行详细介绍:
(1)前序遍历
上图前序遍历顺序为1、2、3、4、5、6
详细解释:
前序遍历的顺序为先从根节点开始,在遍历左子树的子树节点,再遍历右子树的子树节点。(其中遍历左子树的子树节点和遍历右子树的子树节点时也按照先遍历根节点,在遍历左子树再遍历右子树)
1、上图中先从根节点1开始,接下来遍历根节点1的左子树部分,遍历节点2的子树,依次遍历节点2,在遍历节点2的左子树节点3,如下图2
图2
2、遍历完根节点1的左子树部分,接下来遍历右子树部分,遍历方式和第一步相同,如图3
图3
(2)中序遍历
上图中序遍历顺序为3、2、1、5、4、6
详细解释:
中序遍历的顺序是先遍历根节点的左子树部分,在遍历根节点,再遍历根节点的右子树部分。所以先从子树2开始遍历,遍历时也按照左子树–>根节点–>右子树遍历。因此最先遍历是节点3,其次是节点2。遍历完左子树部分遍历完根节点1后开始遍历右子树4部分,遍历效果类似。
(3)后序遍历
上图中序遍历顺序为3、2、5、6、4、1
详细解释:
后序遍历的顺序先遍历根节点的左子树部分,在遍历右子树部分,最后在遍历根节点。因此在上图中最先遍历的节点为节点3,其次为节点2。遍历完左子树后,在遍历右子树部分,于是遍历右子树中最先遍历的是节点4子树中的左子树节点5,其次是右子树节点6,节点4,最后在遍历根节点1。
层序遍历原理
除了前序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。
设二叉树的根节点所在层数为1
,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第
2
层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历
因此层序遍历的遍历顺序为1、2、4、3、5、6
二、二叉树遍历题目推导
1、
某完全二叉树按层次输出(同一层从左到右)的序列为
ABCDEFGH
。该完全二叉树的前序序列为
(
A
)
A: ABDHECFG B: ABCDEFGH C: HDBEAFCG D: HDEBFGCA
解析:根据完全二叉树输出序列可以画出该二叉树结构,如下图

因此可得出前序序列为ABDHECFG
2、
二叉树的先序遍历和中序遍历如下:先序遍历:
EFHIGJK;
中序遍历:
HFIEJKG.
则二叉树根结点为
(
A
)
A: E B: F C: G D: H
解析:根据题目给出的先序遍历和中序遍历,以中序遍历为基础来画出二叉树的结构
(1) 由先序
遍历EFHIGJK可知E为根节点,所以对中序遍历可画出以下图1:

(2)其次可得先序遍历的第二个节点F知节点F为左子树的父节点,并且在中序遍历顺序中节点H和节点I的先后顺序各在节点F的一前一后,所以对图1进行修改得出图2:
(3)剩下节点JKG由先序遍历顺序可得节点G在节点J、K的前面,因此节点G为右子树的父节点。并且中序遍历的顺序中J、K在G的前面,可得节点J、K为节点G的左子树部分,画出图3:
(4)最后根据先序遍历顺序中,K在J的后面,可得节点K是节点J的右子树,画出图4:
至此,二叉树的结构就已经全部画出来了
3、
设一课二叉树的中序遍历序列:
badce
,后序遍历序列:
bdeca
,则二叉树前序遍历序列为
(
D
)
A: adbce B: decab C: debac D: abcde
解析:(1)根据后续遍历序列可得二叉树的根节点为a,于是对中序遍历可得图1:

(2) 根据后续遍历序列可得节点c为父类节点,且在中序遍历序列中d和e排在c的左右两边,于是可得图2:
(3)因此可得该二叉树的前序遍历序列为abcde
4、
某二叉树的后序遍历序列与中序遍历序列相同,均为
ABCDEF
,则按层次输出
(
同一层从左到右
)
的序列为
(
A
)
A: FEDCBA B: CBAFED C: DEFCBA D: ABCDEF
三、二叉树的基本操作
3.1 二叉树的创建
二叉树的存储结构
分为:
顺序存储
和
类似于链表的链式存储
。
二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式。
在这里我们主要使用二叉表示法来创建二叉树。
class Node {
int val; // 数据域
Node left; // 左子树的引用,常常代表为根的整棵左子树
Node right; // 右子树的引用,常常代表为根的整棵右子树
}
3.2 二叉树的创建代码实现
以下图二叉树为例创建
public class BinaryTree {
static class TreeNode{
public int value; //定义每个节点存储的值
public TreeNode left; //定义节点的左子树
public TreeNode right; //定义节点的右子树
public TreeNode(int value) {
this.value = value;
}
}
public TreeNode root;//定义根节点
public void createTree(){
TreeNode A = new TreeNode(1);
TreeNode B = new TreeNode(2);
TreeNode C = new TreeNode(3);
TreeNode D = new TreeNode(4);
TreeNode E = new TreeNode(5);
TreeNode F = new TreeNode(6);
A.left=B;
B.left=C;
A.right=D;
D.left=E;
D.right=F;
this.root=A;
}
3.3 二叉树的基本操作代码实现
3.3.1 前序遍历代码实现 (递归方式)
由于二叉树是递归定义的,所以二叉树的遍历一般也是采用递归的形式,当然二叉树也可以用非递归方式遍历。这里文章用递归方式介绍。前序遍历即采用先访问根节点,再访问左子树,最后访问右子树的顺序。前序遍历也是按照类似的方式递归遍历,具体操作如下:
① 如果当前节点值为空,返回;
②如果当前节点值不为空,打印当前节点值;递归遍历左子树;递归遍历右子树。
public void preOrder(TreeNode root){ //前序遍历:根节点-->左子树-->右子树
if (root == null){
return;
}
System.out.print(root.value+" ");//打印根节点
preOrder(root.left);// 递归遍历左子树
preOrder(root.right);// 递归遍历右子树
}
3.3.2 中序遍历代码实现 (递归方式)
①如果当前节点值为空,返回;
②递归遍历左子树;打印当前节点的值;递归遍历右子树。
public void inOrder(TreeNode root){//中序遍历:左子树-->根节点-->右子树
if (root == null){
return;
}
inOrder(root.left);// 递归遍历左子树
System.out.print(root.value+" ");//打印根节点
inOrder(root.right);// 递归遍历右子树
}
3.3.3 后序遍历代码实现 (递归方式)
①如果当前节点值为空,返回;
②递归遍历左子树;递归遍历右子树;打印当前节点的值。
public void posOrder(TreeNode root){//后序遍历:左子树-->右子树-->根节点
if (root == null){
return;
}
posOrder(root.left);// 递归遍历左子树
posOrder(root.right);// 递归遍历右子树
System.out.print(root.value+" ");//打印根节点
}
3.3.4 获取树中节点的个数
public int size(TreeNode root){
if(root==null){
return 0;
}
int a = size(root.left);// 递归遍历左子树
int b = size(root.right);// 递归遍历右子树
return a+b+1;//树中节点个数为左子树个数+右子树个数+根节点个数
}
3.3.5 获取叶子节点的个数
public int getLeaf(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) { //判断叶子左右节点是否为空,
//若为空则为叶子节点
return 1;
}
int getLeafleft = getLeaf(root.left);
int getLeafright = getLeaf(root.right);
return getLeafleft + getLeafright;
}
3.3.6 获取第K层节点的个数
第K层较于根节点是第K层,但较于根节点的左子树部分是第K-1层(计算层数的起点减一,所以是第K-1层),同理较于根节点的右子树部分是第K-1层。因此在递归左子树和右子树时,获取第K层节点个数就是相当于获取左子树第K-1层节点个数加上右子树第K-1层节点个数。
public int getKLevelNode(TreeNode root,int k){
if (root == null) {
return 0;
}
if (k == 1){
return 1;
}
int getKLevelNodeleft =getKLevelNode(root.left,k-1);//获取左子树第k-1层节点个数
int getKLevelNoderight =getKLevelNode(root.right,k-1);//获取右子树第k-1层节点个数
return getKLevelNodeleft + getKLevelNoderight;
}
3.3.7 获取二叉树的高度
获取二叉树的高度的思路是先比较左子树和右子树的高度,比较两者之间的最大高度加1
public int getHeight(TreeNode root){
if (root == null) {
return 0;
}
int getHeightleft = getHeight(root.left);
int getHeightright = getHeight(root.right);
return (getHeightleft > getHeightright) ? (getHeightleft+1) : (getHeightright+1);
}
3.3.8 检测值为value的元素是否存在
TreeNode find(TreeNode root, int val){
if(root == null){
return null;
}
if(root.value == val){
return root;
}
TreeNode lefttree = find(root.left,val); //左子树查找val,使用lefttree来接收
if(lefttree != null){ //接受值不为null,说明在左子树已经查找到val
return lefttree;
}
TreeNode righttree = find(root.right,val);//右子树查找val,使用righttree来接收
if(righttree != null){ //接受值不为null,说明在右子树已经查找到val
return righttree;
}
return null; //走到这一步说明左右子树都没有找到val,直接返回null
}
3.3.9 二叉树层序遍历
层序遍历的思路:利用队列的性质:先进先出,根节点入队列,当队列不为空时,把队头节点赋值给cur节点并打印。遍历cur节点的左子树不为空时,将左子树节点入队列,判断队列如果不为空,则把队头节点赋值给cur节点,打印cur节点数据域,遍历cur节点的右子树也跟左子树一样。当队列为空时,则二叉树的节点已经全部层序遍历完成。
public void levelOrder(TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();//层序遍历利用队列性质:先进先出 层序遍历二叉树
if(root == null){
return ;
}
queue.offer(root);
while(!queue.isEmpty()){//当队列为空时,二叉树层序遍历就完成了
TreeNode cur = queue.poll(); //当队列不为空时,就把队头的节点赋值给cur,队头节点出队列并打印cur节点数据域
System.out.print(cur.value+" ");
if(cur.left != null){ //节点的左子树不为空时,入队列
queue.offer(cur.left);
}
if(cur.right != null){ //节点的右子树不为空时,入队列
queue.offer(cur.right);
}
}
}
3.4 二叉树基本操作全部代码
import java.util.LinkedList;
import java.util.Queue;
public class BinaryTree {
static class TreeNode {
public int value; //定义每个节点存储的值
public TreeNode left; //定义节点的左子树
public TreeNode right; //定义节点的右子树
public TreeNode(int value) {
this.value = value;
}
}
public TreeNode root;//定义根节点
public void createTree() {
TreeNode A = new TreeNode(1);
TreeNode B = new TreeNode(2);
TreeNode C = new TreeNode(3);
TreeNode D = new TreeNode(4);
TreeNode E = new TreeNode(5);
TreeNode F = new TreeNode(6);
A.left = B;
B.left = C;
A.right = D;
D.left = E;
D.right = F;
this.root = A;
}
/*
* 前序遍历(递归方式)
* */
public void preOrder(TreeNode root) { //前序遍历:根节点-->左子树-->右子树
if (root == null) {
return;
}
System.out.print(root.value + " ");//打印根节点
preOrder(root.left);// 递归遍历左子树
preOrder(root.right);// 递归遍历右子树
}
/*
* 中序遍历(递归方式)
* */
public void inOrder(TreeNode root) {//中序遍历:左子树-->根节点-->右子树
if (root == null) {
return;
}
inOrder(root.left);// 递归遍历左子树
System.out.print(root.value + " ");//打印根节点
inOrder(root.right);// 递归遍历右子树
}
/*
* 后序遍历(递归方式)
* */
public void posOrder(TreeNode root) {//后序遍历:左子树-->右子树-->根节点
if (root == null) {
return;
}
posOrder(root.left);// 递归遍历左子树
posOrder(root.right);// 递归遍历右子树
System.out.print(root.value + " ");//打印根节点
}
/*
* 获取树中节点的个数*/
public int size(TreeNode root) {
if (root == null) {
return 0;
}
int a = size(root.left);// 递归遍历左子树
int b = size(root.right);// 递归遍历右子树
return a + b + 1;//树中节点个数为左子树个数+右子树个数+根节点个数
}
/*
* 获取叶子节点个数*/
public int getLeaf(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) { //判断叶子左右节点是否为空,若为空则为叶子节点
return 1;
}
int getLeafleft = getLeaf(root.left);
int getLeafright = getLeaf(root.right);
return getLeafleft + getLeafright;
}
/*
* 获取第K层节点个数*/
public int getKLevelNode(TreeNode root,int k){
if (root == null) {
return 0;
}
if (k == 1){
return 1;
}
int getKLevelNodeleft =getKLevelNode(root.left,k-1);//获取左子树第k-1层节点个数
int getKLevelNoderight =getKLevelNode(root.right,k-1);//获取右子树第k-1层节点个数
return getKLevelNodeleft + getKLevelNoderight;
}
/*
* 获取二叉树的高度*/
public int getHeight(TreeNode root){
if (root == null) {
return 0;
}
int getHeightleft = getHeight(root.left);
int getHeightright = getHeight(root.right);
return (getHeightleft > getHeightright) ? (getHeightleft+1) : (getHeightright+1);
}
/*
* 检测值为value的元素是否存在并返回对应的节点*/
TreeNode find(TreeNode root, int val){
if(root == null){
return null;
}
if(root.value == val){
return root;
}
TreeNode lefttree = find(root.left,val); //左子树查找val,使用lefttree来接收
if(lefttree != null){ //接受值不为null,说明在左子树已经查找到val
return lefttree;
}
TreeNode righttree = find(root.right,val);//右子树查找val,使用righttree来接收
if(righttree != null){ //接受值不为null,说明在右子树已经查找到val
return righttree;
}
return null; //走到这一步说明左右子树都没有找到val,直接返回null
}
/*
* 二叉树的层序遍历*/
public void levelOrder(TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();//层序遍历利用队列性质:先进先出 层序遍历二叉树
if(root == null){
return ;
}
queue.offer(root);
while(!queue.isEmpty()){//当队列为空时,二叉树层序遍历就完成了
TreeNode cur = queue.poll(); //当队列不为空时,就把队头的节点赋值给cur,队头节点出队列并打印cur节点数据域
System.out.print(cur.value+" ");
if(cur.left != null){ //节点的左子树不为空时,入队列
queue.offer(cur.left);
}
if(cur.right != null){ //节点的右子树不为空时,入队列
queue.offer(cur.right);
}
}
}
}
测试代码运行结果
public class Test {
public static void main(String[] args) {
BinaryTree binaryTree = new BinaryTree();
binaryTree.createTree();
System.out.print("前序遍历:");
binaryTree.preOrder(binaryTree.root);
System.out.println();
System.out.print("中序遍历:");
binaryTree.inOrder(binaryTree.root);
System.out.println();
System.out.print("后序遍历:");
binaryTree.posOrder(binaryTree.root);
System.out.println();
System.out.println("================");
int totalSize = binaryTree.size(binaryTree.root);
System.out.println("树中节点的个数:"+totalSize);
int c= binaryTree.getLeaf(binaryTree.root);
System.out.println("树中叶子节点个数:"+c);
int getKLevelNodesize=binaryTree.getKLevelNode(binaryTree.root,2);
System.out.println("第K层节点个数:"+getKLevelNodesize);
int getHeightsize = binaryTree.getHeight(binaryTree.root);
System.out.println("二叉树的高度:"+getHeightsize);
System.out.print("二叉树层序遍历:");
binaryTree.levelOrder(binaryTree.root);
}
}