第 21 天: 二叉树的深度遍历的递归实现
21.1 二叉树的遍历比存储、建立要简单. 所以先“手动”建立一个二叉树来玩.
21.2 递归算法写起来就是舒服. 前、中、后序的代码差别只有输出语句的位置.
21.3 不需要额外的节点类, 每棵二叉树 (树) 都可以从自己的根结点找到其它所有节点. 这个需要自悟.
21.4 获取二叉树的层次、总节点数, 也需要递归. 以后可能要用, 这里就一并写了.
package datastructures.tree;
/**
* ClassName: BinaryCharTree
* Package: datastructures.tree
* Description: Binary tree with char type elements.
*
* @Author: luv_x_c
* @Create: 2023/4/25 14:44
*/
public class BinaryCharTree {
/**
* 二叉树的根节点
*/
private BinaryTreeNode root;
private static class BinaryTreeNode {
/**
* The value in char.
*/
private char value;
/**
* The left child.
*/
private BinaryTreeNode left;
/**
* The right child.
*/
private BinaryTreeNode right;
/**
* A constructor.
*
* @param paraValue The given value.
*/
public BinaryTreeNode(char paraValue) {
this.value = paraValue;
this.left = null;
this.right = null;
}//
}// Of class BinaryTreeNode
/**
* 构造函数
*/
public BinaryCharTree() {
root = null;
}
/**
* ********************
* Manually construct a tree. Only for testing.
* ********************
*/
public static BinaryCharTree manualConstructTree() {
// Step 1. Construct a null tree.
BinaryCharTree resultTree = new BinaryCharTree();
// Step 2. Construct all nodes. The first node is the root.
BinaryTreeNode tempNodeA = new BinaryTreeNode('a');
BinaryTreeNode tempTreeB = new BinaryTreeNode('b');
BinaryTreeNode tempTreeC = new BinaryTreeNode('c');
BinaryTreeNode tempTreeD = new BinaryTreeNode('d');
BinaryTreeNode tempTreeE = new BinaryTreeNode('e');
BinaryTreeNode tempTreeF = new BinaryTreeNode('f');
BinaryTreeNode tempTreeG = new BinaryTreeNode('g');
// Step 3. Link all nodes.
tempNodeA.left = tempTreeB;
tempNodeA.right = tempTreeC;
tempTreeB.left = tempTreeD;
tempTreeB.right = tempTreeE;
tempTreeC.left = tempTreeF;
tempTreeC.right = tempTreeG;
resultTree.root = tempNodeA;
return resultTree;
}// Of manualConstructTree
/**
* 先序遍历
*/
public void preOrderVisit() {
preOrderVisit(root);
}// Of preOrderVisit
private void preOrderVisit(BinaryTreeNode paraRoot) {
if (paraRoot != null) {
System.out.print("" + paraRoot.value + " ");
preOrderVisit(paraRoot.left);
preOrderVisit(paraRoot.right);
}// Of if
}// Of preOrderVisit
/**
* 中序遍历
*/
public void inOrderVisit() {
inOrderVisit(root);
}
private void inOrderVisit(BinaryTreeNode paraRoot) {
if (paraRoot != null) {
inOrderVisit(paraRoot.left);
System.out.print("" + paraRoot.value + " ");
inOrderVisit(paraRoot.right);
}// Of if
}// Of inOrderVisit
/**
* 后序遍历
*/
public void postOrderVisit() {
postOrderVisit(root);
}
private void postOrderVisit(BinaryTreeNode paraRoot) {
if (paraRoot != null) {
postOrderVisit(paraRoot.left);
postOrderVisit(paraRoot.right);
System.out.print("" + paraRoot.value + " ");
}// Of if
}// Of postOrderVisit
// 计算树的高度
public int getDepth() {
return getDepth(root);
}
private int getDepth(BinaryTreeNode paraRoot) {
return paraRoot == null ? 0 : 1 + Math.max(getDepth(paraRoot.left), getDepth(paraRoot.right));
}
/**
* Get the number of nodes.
*
* @return The number of nodes.
*/
public int getNumNodes() {
return getNumNodes(root);
}
private int getNumNodes(BinaryTreeNode paraRoot) {
if (paraRoot == null) {
return 0;
} else {
return 1 + getNumNodes(paraRoot.left) + getNumNodes(paraRoot.right);
}
}// Of getNumNodes
/**
* The entrance of the program.
*
* @param args Not used now.
*/
public static void main(String[] args) {
BinaryCharTree tree = manualConstructTree();
System.out.println("The tree's depth is: " + tree.getDepth());
System.out.print("preOrderVisit is: ");
tree.preOrderVisit();
System.out.println();
System.out.print("inOrderVisit is: ");
tree.inOrderVisit();
System.out.println();
System.out.print("postOrderVisit is: ");
tree.postOrderVisit();
System.out.println("\nThe number of nodes is: " + tree.getNumNodes());
}// Of main
}// Of class BinaryCharTree
老师原本的意思不要结点类,但是加上之后我感觉操作会顺滑一点(也可能是我太菜了)。比如递归遍历和求高之类的直接用判断根节点空,个人感觉比较简洁一些吧。
但是老师的代码里面那样没有结点类的话,怎么表示空树,新建一个二叉树对象就要传进去一个结点值,那一开始就不空了...
下面附上老师的代码
package datastructure.tree;
import java.util.Arrays;
/**
* Binary tree with char type elements.
*
* @author Fan Min minfanphd@163.com.
*/
public class BinaryCharTree {
/**
* The value in char.
*/
char value;
/**
* The left child.
*/
BinaryCharTree leftChild;
/**
* The right child.
*/
BinaryCharTree rightChild;
/**
*********************
* The first constructor.
*
* @param paraName
* The value.
*********************
*/
public BinaryCharTree(char paraName) {
value = paraName;
leftChild = null;
rightChild = null;
}// Of the constructor
/**
*********************
* Manually construct a tree. Only for testing.
*********************
*/
public static BinaryCharTree manualConstructTree() {
// Step 1. Construct a tree with only one node.
BinaryCharTree resultTree = new BinaryCharTree('a');
// Step 2. Construct all nodes. The first node is the root.
// BinaryCharTreeNode tempTreeA = resultTree.root;
BinaryCharTree tempTreeB = new BinaryCharTree('b');
BinaryCharTree tempTreeC = new BinaryCharTree('c');
BinaryCharTree tempTreeD = new BinaryCharTree('d');
BinaryCharTree tempTreeE = new BinaryCharTree('e');
BinaryCharTree tempTreeF = new BinaryCharTree('f');
BinaryCharTree tempTreeG = new BinaryCharTree('g');
// Step 3. Link all nodes.
resultTree.leftChild = tempTreeB;
resultTree.rightChild = tempTreeC;
tempTreeB.rightChild = tempTreeD;
tempTreeC.leftChild = tempTreeE;
tempTreeD.leftChild = tempTreeF;
tempTreeD.rightChild = tempTreeG;
return resultTree;
}// Of manualConstructTree
/**
*********************
* Pre-order visit.
*********************
*/
public void preOrderVisit() {
System.out.print("" + value + " ");
if (leftChild != null) {
leftChild.preOrderVisit();
} // Of if
if (rightChild != null) {
rightChild.preOrderVisit();
} // Of if
}// Of preOrderVisit
/**
*********************
* In-order visit.
*********************
*/
public void inOrderVisit() {
if (leftChild != null) {
leftChild.inOrderVisit();
} // Of if
System.out.print("" + value + " ");
if (rightChild != null) {
rightChild.inOrderVisit();
} // Of if
}// Of inOrderVisit
/**
*********************
* Post-order visit.
*********************
*/
public void postOrderVisit() {
if (leftChild != null) {
leftChild.postOrderVisit();
} // Of if
if (rightChild != null) {
rightChild.postOrderVisit();
} // Of if
System.out.print("" + value + " ");
}// Of postOrderVisit
/**
*********************
* Get the depth of the binary tree.
*
* @return The depth. It is 1 if there is only one node, i.e., the root.
*********************
*/
public int getDepth() {
// It is a leaf.
if ((leftChild == null) && (rightChild == null)) {
return 1;
} // Of if
// The depth of the left child.
int tempLeftDepth = 0;
if (leftChild != null) {
tempLeftDepth = leftChild.getDepth();
} // Of if
// The depth of the right child.
int tempRightDepth = 0;
if (rightChild != null) {
tempRightDepth = rightChild.getDepth();
} // Of if
// The depth should increment by 1.
if (tempLeftDepth >= tempRightDepth) {
return tempLeftDepth + 1;
} else {
return tempRightDepth + 1;
} // Of if
}// Of getDepth
/**
*********************
* Get the number of nodes.
*
* @return The number of nodes.
*********************
*/
public int getNumNodes() {
// It is a leaf.
if ((leftChild == null) && (rightChild == null)) {
return 1;
} // Of if
// The number of nodes of the left child.
int tempLeftNodes = 0;
if (leftChild != null) {
tempLeftNodes = leftChild.getNumNodes();
} // Of if
// The number of nodes of the right child.
int tempRightNodes = 0;
if (rightChild != null) {
tempRightNodes = rightChild.getNumNodes();
} // Of if
// The total number of nodes.
return tempLeftNodes + tempRightNodes + 1;
}// Of getNumNodes
/**
*********************
* The entrance of the program.
*
* @param args
* Not used now.
*********************
*/
public static void main(String args[]) {
BinaryCharTree tempTree = manualConstructTree();
System.out.println("\r\nPreorder visit:");
tempTree.preOrderVisit();
System.out.println("\r\nIn-order visit:");
tempTree.inOrderVisit();
System.out.println("\r\nPost-order visit:");
tempTree.postOrderVisit();
System.out.println("\r\n\r\nThe depth is: " + tempTree.getDepth());
System.out.println("The number of nodes is: " + tempTree.getNumNodes());
}// Of main
}// Of BinaryCharTree