二叉树
节点结构
class TreeNode{
public int value;
public TreeNode left;
public TreeNode right;
TreeNode(int value){
this.value = value;
}
}
二叉树结尾指向 null;
左孩子 右孩子都为空,表示叶子节点;
根节点或者叫头节点;
二叉树
假设一个二叉树结构, 如下图:
二叉树的遍历递归实现
TreeTest.java 可以看代码注释 中序遍历的栈的方法, 打印方式不同,
if (headNode != null) {
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || headNode != null) {
if (headNode != null) {
stack.push(headNode);
headNode = headNode.left;
} else {
headNode = stack.pop();
System.out.print(headNode.value + ",");
headNode = headNode.right;
}
}
}
-
先序遍历(根左右): 在递归序的链表下, 第一次出现的打印,重复出现都不打印,得到的结果;
-
中序遍历(左根右): 在递归序的链表下, 只有第二次出现的打印, 其他不打印,得的结果;
-
后续遍历(左右根): 在递归序的链表下, 只有第三次出现打印,其他不打印,得到的结果;
二叉树栈实现;
先序遍历:根左右
-
从栈中弹出 current 节点
-
打印 current
-
把当前节点先压右 再压左(如果有)
-
重复以上操作
/**
* 前序
*
* @param headNode
*/
public void preOrderRecur1(TreeNode headNode) {
if (headNode != null) {
Stack<TreeNode> stack = new Stack<>();
stack.push(headNode);
while (!stack.isEmpty()) {
//打印当前节点的时候,当前结点的右结点 、 左结点进栈;
headNode = stack.pop();
System.out.print(headNode.value + ",");
if (headNode.right != null) {
stack.push(headNode.right);
}
if (headNode.left != null) {
stack.push(headNode.left);
}
}
}
}
中序遍历: 左根右
-
每颗子树,整个树左边界进站;
-
依次弹出节点的过程中,打印(处理),对弹出节点右树 周而复始;
/**
* 中序
*
* @param headNode
*/
public void midOrderRecur1(TreeNode headNode) {
if (headNode != null) {
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || headNode != null) {
if (headNode != null) {
stack.push(headNode);
headNode = headNode.left;
} else {
headNode = stack.pop();
System.out.print(headNode.value + ",");
headNode = headNode.right;
}
}
}
}
后序遍历:左右根
-
两个栈;
-
第一个栈入栈顺序是 先压左 后压右;
-
第二个栈 是第一个栈的逆序,就是先压右边,在压左;最后出栈就是左右头;
操作顺序
-
弹出 current
-
把current 压入第二个栈
-
先压左再压右边;
-
重复以上顺序;
TreeTest.java 代码递归和栈实现二叉树的三种遍历
import java.util.Stack;
class TreeTest {
/**
*
*
*
* @param args
*/
public static void main(String args[]) {
TreeNode headNode = new TreeNode(5);
headNode.left = new TreeNode(3);
headNode.right = new TreeNode(8);
headNode.left.left = new TreeNode(2);
headNode.left.right = new TreeNode(4);
headNode.left.left.left = new TreeNode(1);
headNode.right.left = new TreeNode(7);
headNode.right.left.left = new TreeNode(6);
headNode.right.right = new TreeNode(10);
headNode.right.right.left = new TreeNode(9);
headNode.right.right.right = new TreeNode(11);
System.out.println("前序遍历 --->");
new TreeTest().preOrderRecur(headNode);
System.out.println("\n");
new TreeTest().preOrderRecur1(headNode);
System.out.println("\n");
System.out.println("中序遍历 --->");
new TreeTest().midOrderRecur(headNode);
System.out.println("\n");
new TreeTest().midOrderRecur1(headNode);
System.out.println("\n");
System.out.println("后序遍历 --->");
new TreeTest().endOrderRecur(headNode);
System.out.println("\n");
new TreeTest().endOrderRecur1(headNode);
System.out.println("\n");
}
/**
* 递归顺序
*
* @param headNode
*/
public void f(TreeNode headNode) {
if (headNode == null) {
return;
}
// 第一次出现 节点
f(headNode.left);
// 第二次出现 节点
f(headNode.right);
// 第三次出现 节点
}
/**
* 先序遍历
*
* 根左右
*
* @param headNode
*/
public void preOrderRecur(TreeNode headNode) {
if (headNode == null) {
return;
}
// 第一次出现 节点 入栈时打印当前结点
System.out.print(headNode.value + " , ");
preOrderRecur(headNode.left);
// 第二次出现 节点
preOrderRecur(headNode.right);
// 第三次出现 节点
}
/**
* 中序遍历
*
* 左根右
*
* @param headNode
*/
public void midOrderRecur(TreeNode headNode) {
if (headNode == null) {
return;
}
// 第一次出现 节点
midOrderRecur(headNode.left);
// 第二次出现 节点 左结点出站,右结点入栈的时候打印当前结点
System.out.print(headNode.value + " , ");
midOrderRecur(headNode.right);
// 第三次出现 节点
}
/**
* 后序遍历
*
* 左右根
*
* @param headNode
*/
public void endOrderRecur(TreeNode headNode) {
if (headNode == null) {
return;
}
// 第一次出现 节点
endOrderRecur(headNode.left);
// 第二次出现 节点
endOrderRecur(headNode.right);
// 第三次出现 节点 出栈的时候打印当前就是后序遍历
System.out.print(headNode.value + " , ");
}
/**
* 前序
*
* @param headNode
*/
public void preOrderRecur1(TreeNode headNode) {
if (headNode != null) {
Stack<TreeNode> stack = new Stack<>();
stack.push(headNode);
while (!stack.isEmpty()) {
//
headNode = stack.pop();
System.out.print(headNode.value + ",");
if (headNode.right != null) {
stack.push(headNode.right);
}
if (headNode.left != null) {
stack.push(headNode.left);
}
}
}
}
/**
* 中序
*
* @param headNode
*/
public void midOrderRecur1(TreeNode headNode) {
if (headNode != null) {
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || headNode != null) {
if (headNode != null) {
stack.push(headNode);
headNode = headNode.left;
} else {
headNode = stack.pop();
System.out.print(headNode.value + ",");
headNode = headNode.right;
}
}
}
}
/**
* 后序
*
* @param headNode
*/
public void endOrderRecur1(TreeNode headNode) {
if (headNode != null) {
Stack<TreeNode> stack1 = new Stack<>();
Stack<TreeNode> stack2 = new Stack<>();
stack1.push(headNode);
while (!stack1.isEmpty()) {
headNode = stack1.pop();
stack2.push(headNode);
if (headNode.left != null) {
stack1.push(headNode.left);
}
if (headNode.right != null) {
stack1.push(headNode.right);
}
}
while (!stack2.isEmpty()) {
System.out.print(stack2.pop().value + ",");
}
}
}
// 有序数组转二叉树 二分法数组
public TreeNode sortedArrayToBST(int[] nums) {
return helper(nums, 0, nums.length - 1);
}
public TreeNode helper(int[] nums, int left, int right) {
if (left > right) {
return null;
}
// 总是选择中间位置左边的数字作为根节点
int mid = (left + right) / 2;
TreeNode root = new TreeNode(nums[mid]);
root.left = helper(nums, left, mid - 1);
root.right = helper(nums, mid + 1, right);
return root;
}
}