目录
一、二叉树的遍历
二叉树的遍历分为以下三种:
前序遍历:访问顺序为 根节点---->左子树---->右子树
中序遍历:访问顺序为 左子树--->根节点---->右子树
后序遍历:访问顺序为 左子树--->右子树---->根节点
接下来针对这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、4、3、5、6
二、二叉树遍历题目推导
![](https://i-blog.csdnimg.cn/blog_migrate/8579b645dde0ed6ea61b4b6cb0e0c620.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4a4c44b95885a06277cd5fc3b78b1b79.png)
(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:
至此,二叉树的结构就已经全部画出来了
![](https://i-blog.csdnimg.cn/blog_migrate/88163d8fa84c8dddad8e6fa790beb1d9.png)
(3)因此可得该二叉树的前序遍历序列为abcde
三、二叉树的基本操作
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);
}
}