package xcc.test;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
import xcc.bean.TreeNode;
public class TestErCha {
/**
* 第一种求二叉树节点个数(利用递归)
* (1)如果二叉树为空,节点个数为0
* (2)如果二叉树不为空,则节点个数=左子树节点+右子树节点+1
* 原理:递归中的root.left和root.right进行子节点的查找。之后进行+1操作
*/
public static int getNodeNumRec(TreeNode root) {
if (root == null) {
return 0;
} else {
return getNodeNumRec(root.left) + getNodeNumRec(root.right) + 1;
}
}
/**
* 第二种求二叉树节点个数(利用迭代)
* (1)从队头位置移除
* (2)如果有左孩子,加到队尾
* (3)如果有右孩子,加到队尾
* 原理:从对头开始移除,如果包含左节点,则添加在queue中,包含右节点,则添加在queue中,并移除当前节点。
*/
public static int getNodeNumIte(TreeNode root){
if(root == null){
return 0;
}
int count = 1;
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
while(!queue.isEmpty()){
TreeNode treeNode = queue.remove();
if(treeNode.left != null){
queue.add(treeNode.left);
count++;
}
if(treeNode.right != null){
queue.add(treeNode.right);
count++;
}
}
return count;
}
/**
* 第一种求二叉树深度(利用递归)
* (1)如果二叉树为空,深度为0
* (2)如果二叉树不为空,二叉树的深度 = max(左子树深度, 右子树深度) + 1
*/
public static int getDepthRec(TreeNode root) {
if (root == null) {
return 0;
}
int left = getDepthRec(root.left);
int right = getDepthRec(root.right);
return Math.max(left, right) + 1;
}
/**
* 第二种求二叉树深度(利用迭代)
* (1)首先移除对头
* (2)减少当前node数量
* (3)如果有左右节点,则需要加左右节点追加到queue中,并记录个数
* (4)当前node数量为0时,证明当前层全部遍历完
* (5)根据记录的个数,进行一层的遍历
*/
public static int getDepthIte(TreeNode root) {
if (root == null) {
return 0;
}
int depth = 0; //深度
int currentLevelNodes = 1; //当前Level,node的数量
int nextLevelNodes = 0; //下一层node的数量
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
while(!queue.isEmpty()){
TreeNode treeNode = queue.remove();
currentLevelNodes--;
if(treeNode.left != null){
queue.add(treeNode.left);
nextLevelNodes++;
}
if(treeNode.right != null){
queue.add(treeNode.right);
nextLevelNodes++;
}
if(currentLevelNodes == 0){// 说明已经遍历完当前层的所有节点
depth++; // 增加高度
currentLevelNodes = nextLevelNodes;// 初始化下一层的遍历
nextLevelNodes = 0;
}
}
return depth;
}
/**
* 第一种前序遍历(递归)
* (1)如果二叉树为空,空操作
* (2)如果二叉树不为空,访问根节点,前序遍历左子树,前序遍历右子树
*/
public static void preorderTraversalRec(TreeNode root) {
if (root == null) {
return;
}
System.out.print(root.val + " ");
preorderTraversalRec(root.left);
preorderTraversalRec(root.right);
}
/**
* 第二种前序遍历(迭代)
* (1)如果二叉树为空,空操作
* (2)借助stack(栈)来实现,先进后出
* (3)先让右孩子就入,再让左孩子进入
*/
public static void preorderTraversalIte(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> stack = new Stack<TreeNode>(); // 辅助stack
stack.push(root);
while( !stack.isEmpty() ){
TreeNode cur = stack.pop(); // 出栈栈顶元素
System.out.print(cur.val + " ");
// 关键点:要先压入右孩子,再压入左孩子,这样在出栈时会先打印左孩子再打印右孩子
if(cur.right != null){
stack.push(cur.right);
}
if(cur.left != null){
stack.push(cur.left);
}
}
}
/**
* 第一种中序遍历(递归)
* (1)如果二叉树为空,空操作
* (2)如果二叉树不为空,中序遍历左子树, 访问根节点,中序遍历右子树
*/
public static void inorderTraversalRec(TreeNode root) {
if (root == null) {
return;
}
inorderTraversalRec(root.left);
System.out.print(root.val + " ");
inorderTraversalRec(root.right);
}
/**
* 第二种中序遍历(迭代)
* (1)用栈先把根节点的所有左孩子都添加到栈内
* (2)然后输出栈顶元素,再处理栈顶元素的右子树
*/
public static void inorderTraversalIte(TreeNode root){
if(root == null){
return;
}
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode cur = root;
while( true ){
while(cur != null){ // 先添加一个非空节点所有的左孩子到栈
stack.push(cur);
cur = cur.left;
}
if(stack.isEmpty()){
break;
}
// 因为此时已经没有左孩子了,所以输出栈顶元素
cur = stack.pop();
System.out.print(cur.val + " ");
cur = cur.right; // 准备处理右子树
}
}
/**
* 第一种后序遍历(递归)
* (1)如果二叉树为空,空操作
* (2)如果二叉树不为空,后序遍历左子树,后序遍历右子树,访问根节点
*/
public static void postorderTraversalRec(TreeNode root) {
if (root == null) {
return;
}
postorderTraversalRec(root.left);
postorderTraversalRec(root.right);
System.out.print(root.val + " ");
}
/**
* 第二种后序遍历(迭代)
* (1)如果二叉树为空,空操作
* (2)如果二叉树不为空,后序遍历左子树,后序遍历右子树,访问根节点
*/
public static void postorderTraversalIte(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> s = new Stack<TreeNode>(); // 第一个stack用于添加node和它的左右孩子
Stack<TreeNode> output = new Stack<TreeNode>();// 第二个stack用于翻转第一个stack输出
s.push(root);
while( !s.isEmpty() ){ // 确保所有元素都被翻转转移到第二个stack
TreeNode cur = s.pop(); // 把栈顶元素添加到第二个stack
output.push(cur);
if(cur.left != null){ // 把栈顶元素的左孩子和右孩子分别添加入第一个stack
s.push(cur.left);
}
if(cur.right != null){
s.push(cur.right);
}
}
while( !output.isEmpty() ){ // 遍历输出第二个stack,即为后序遍历
System.out.print(output.pop().val + " ");
}
}
public static void main(String[] args) {
/*
1
/ \
2 3
/ \ \
4 5 6
*/
TreeNode r1 = new TreeNode(1);
TreeNode r2 = new TreeNode(2);
TreeNode r3 = new TreeNode(3);
TreeNode r4 = new TreeNode(4);
TreeNode r5 = new TreeNode(5);
TreeNode r6 = new TreeNode(6);
r1.left = r2;
r1.right = r3;
r2.left = r4;
r2.right = r5;
r3.right = r6;
TestErCha.postorderTraversalRec(r1);
}
}
二叉树 求节点、深度、前序、中序、后序遍历
最新推荐文章于 2019-04-16 11:37:30 发布