前言:二叉树的遍历、前序、中序、后序、层次遍历、递归写法与循环写法
提示:java编写,以后考虑用c++重写
二叉树的定义
class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
构建二叉排序树
按顺序递归构建二叉排序树
注:按顺序构建,根节点已经固定
用例:
7
5 3 2 1 6 7 4
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
TreeNode root = new TreeNode(arr[0]); // 构建根结点
for (int i = 1; i < n; i++) {
sortBinaryTree(root, arr[i]);
}
preOrder(root);
System.out.println();
Arrays.sort(arr); // 先排序
TreeNode minHeightTree = createMinHeightTree(arr, 0, arr.length - 1);
preOrder(minHeightTree);
}
}
public static void preOrder(TreeNode node){
if(node != null){
System.out.print(node.val + " ");
preOrder(node.left);
preOrder(node.right);
}
}
public static TreeNode sortBinaryTree(TreeNode node, int i) {
if (node == null) {
node = new TreeNode(i);
return node;
} else {
if (i <= node.val) {
node.left = sortBinaryTree(node.left, i);
} else {
node.right = sortBinaryTree(node.right, i);
}
return node;
}
}
}
构建最小高度的二叉排序树
注:首先要排序,然后从中间取。递归
public static TreeNode createMinHeightTree(int[] a, int start, int end){
if(start > end)
return null;
int mid = start + (end - start)/2;
TreeNode node = new TreeNode(a[mid]);
node.left = createMinHeightTree(a, start, mid-1);
node.right = createMinHeightTree(a, mid+1, end);
return node;
}
二叉树的遍历相关部分
import java.util.*;
//树的层次遍历
public class Solution {
public TreeNode createBinaryTree() {
TreeNode root = new TreeNode(1);
TreeNode p2 = new TreeNode(2);
TreeNode p3 = new TreeNode(3);
TreeNode p4 = new TreeNode(4);
TreeNode p5 = new TreeNode(5);
TreeNode p6 = new TreeNode(6);
TreeNode p7 = new TreeNode(7);
// 组合 1
// 2 3
// 4 5 # 7
// # # 6
root.left = p2;
root.right = p3;
p2.left = p4;
p2.right = p5;
p3.right = p7;
p5.left = p6;
return root;
}
public static void main(String[] args) {
Solution solution = new Solution();
TreeNode root = solution.createBinaryTree();
// 先序递归遍历
List<Integer> res = new ArrayList<>();
System.out.println("*******先序**************************");
solution.preOrderRecur(root, res);
System.out.println(res);
System.out.println("*********************************");
res = solution.preOrderLoop(root);
System.out.println(res);
System.out.println("*******中序**************************");
res.clear();
solution.InOrderRecur(root, res);
System.out.println(res);
System.out.println("*********************************");
res = solution.InOrderLoop(root);
System.out.println(res);
System.out.println("*******后序**************************");
res.clear();
solution.PostOrderRecur(root, res);
System.out.println(res);
res = solution.PostOrderLoop(root);
System.out.println(res);
System.out.println("*******深度**************************");
int depth = solution.depth(root);
System.out.println(depth);
System.out.println("*******层次遍历**************************");
res.clear();
solution.levelOrder(root, res);
System.out.println(res);
System.out.println("*******层次遍历从左到右**************************");
List<List<Integer>> ret = solution.levelOrder(root);
for (List<Integer> sub : ret)
System.out.println(sub);
System.out.println("*******层次遍历之字形**************************");
ret = solution.Print(root);
for (List<Integer> sub : ret)
System.out.println(sub);
}
}
先序遍历
// 递归先序
public void preOrderRecur(TreeNode root, List<Integer> list) {
if (root == null)
return;
list.add(root.val);
preOrderRecur(root.left, list);
preOrderRecur(root.right, list);
}
// 循环先序, 需要借助栈
public List<Integer> preOrderLoop(TreeNode root) {
List<Integer> list = new ArrayList<Integer>();
if (root == null)
return list;
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = root;
while (!stack.isEmpty() || p != null) {
if (p != null) {
stack.push(p); // 保存结点的原因是要回退到上一结点
list.add(p.val); // 保存结点的同时就取值
p = p.left;
} else {
p = stack.pop();
p = p.right;
}
}
return list;
}
中序遍历
// 中序遍历递归
public void InOrderRecur(TreeNode root, List<Integer> list) {
if (root == null)
return;
InOrderRecur(root.left, list);
list.add(root.val);
InOrderRecur(root.right, list);
}
// 中序循环,从这里就看出中序循环与先序多么类似
public List<Integer> InOrderLoop(TreeNode root) {
List<Integer> list = new ArrayList<>();
if (root == null)
return list;
Stack<TreeNode> stack = new Stack<>();
TreeNode p = root;
while (!stack.isEmpty() || p != null) {
if (p != null) {
stack.push(p); // 先添加结点
p = p.left;
} else {
p = stack.pop();
list.add(p.val); // 后才考虑取出结点得出值
p = p.right;
}
}
return list;
}
后序遍历
// 后序递归遍历
public void PostOrderRecur(TreeNode root, List<Integer> list) {
if (root == null)
return;
PostOrderRecur(root.left, list);
PostOrderRecur(root.right, list);
list.add(root.val);
}
// 后序循环遍历,比前面的循环遍历要麻烦些,仍然使用栈,额外需要辅助:上一个结点、当前节点
public List<Integer> PostOrderLoop(TreeNode root) {
List<Integer> list = new ArrayList<>();
if (root == null)
return list;
Stack<TreeNode> stack = new Stack<>();
TreeNode p = root, pre = null, cur = null;
while (!stack.isEmpty() || p != null) {
if (p != null) {
stack.push(p); // 这里和中序类似
p = p.left;
} else {
cur = stack.peek();
if (pre != cur.right && cur.right != null) {
// 若上一个结点不是当前节点的右结点(必须这样判断),且当前节点的右结点存在
// 从左结点往上需要考虑父结点是否存在右子树;从右结点往上直接退,直到当前节点为父结点的左子结点
p = cur.right;
} else {
pre = stack.pop(); // 保存上一个结点
list.add(pre.val); // 存值
}
}
}
return list;
}
数的深度
// 递归求取深度,但仍存在树太深,递归栈溢出问题
public int depth(TreeNode root) {
if (root == null)
return 0;
return Math.max(depth(root.left), depth(root.right)) + 1;
}
层次遍历
// 层次遍历, 遍历结果加到一个数组
public void levelOrder(TreeNode root, List<Integer> list) {
if (root == null)
return;
Deque<TreeNode> deque = new ArrayDeque<>();
deque.offer(root);
TreeNode p = null;
while (!deque.isEmpty()) {
p = deque.poll();
list.add(p.val);
if (p.left != null)
deque.offer(p.left);
if (p.right != null)
deque.offer(p.right);
}
}
/*
* 后续是补充的一些改进方法,有些是剑指offer上,不属于主要遍历方式
* */
// 层次遍历,这里改进,每层按之字形
public List<List<Integer>> Print(TreeNode root) {
List<List<Integer>> ret = new ArrayList<>();
if (root == null)
return ret;
boolean even = true;
Deque<TreeNode> deque = new ArrayDeque<>();
deque.add(root);
TreeNode p = null;
int curSize = 0;
while (!deque.isEmpty()) {
curSize = deque.size(); // 初始化每层结点个数
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < curSize; i++) {
p = deque.poll();
if (even) {
list.add(p.val); // 偶数往后添加
} else {
list.add(0, p.val); // 奇数前插
}
if (p.left != null)
deque.add(p.left);
if (p.right != null)
deque.add(p.right);
}
ret.add(list);
even = !even; // 转换每层方向
}
return ret;
}
// 层次遍历, 遍历结果按层存放
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null)
return res;
dfs(res, root, 0); // 第一层为0层
return res;
}
// 辅助的dfs
private void dfs(List<List<Integer>> res, TreeNode node, int level) {
if (res.size() < level + 1) {
res.add(new ArrayList<Integer>()); // 这里有多深就创建了多少层
}
res.get(level).add(node.val);
if (node.left != null) {
dfs(res, node.left, level + 1);
}
if (node.right != null) {
dfs(res, node.right, level + 1);
}
}