前言
常规递归和非递归方法
import java.io.*; import java.util.Stack; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); br.readLine(); TreeNode root = buildTree(br); // 前序遍历 //preOrderTraversalRecur(root); preOrderTraversal(root); System.out.println(""); // 中序遍历 //inOrderTraversalRecur(root); inOrderTraversal(root); System.out.println(""); // 后序遍历 //postOrderTraversalRecur(root); postOrderTraversal2(root); System.out.println(""); br.close(); } // 递归解法 private static void preOrderTraversalRecur(TreeNode root) { if (null == root) { return; } System.out.print(root.val + " "); preOrderTraversalRecur(root.left); preOrderTraversalRecur(root.right); } // 非递归前序遍历解法, 根左右 private static void preOrderTraversal(TreeNode root) { if (null == root) { return ; } Stack<TreeNode> stack = new Stack<>(); TreeNode cur = root, last = root; // 记录上次遍历的 节点 stack.push(cur); while (!stack.isEmpty()) { cur = stack.pop(); System.out.print(cur.val + " "); if (null != cur.right) { stack.push(cur.right); } if (null != cur.left) { stack.push(cur.left); } } return; } private static void inOrderTraversalRecur(TreeNode root) { if (null == root) { return; } preOrderTraversalRecur(root.left); System.out.print(root.val + " "); preOrderTraversalRecur(root.right); } // 非递归中序遍历解法, 用栈实现, 左根右 private static void inOrderTraversal(TreeNode root) { if (null == root) { return; } Stack<TreeNode> stack = new Stack<>(); TreeNode cur = root; while (!stack.isEmpty() || null != cur) { while (null != cur) { stack.push(cur); cur = cur.left; } cur = stack.pop(); System.out.print(cur.val + " "); cur = cur.right; } return ; } private static void postOrderTraversalRecur(TreeNode root) { if (null == root) { return; } preOrderTraversalRecur(root.left); preOrderTraversalRecur(root.right); System.out.print(root.val + " "); } // 非递归后序遍历解法,左右根,参考左的书籍 // 用一个栈实现的版本 private static void postOrderTraversal(TreeNode root) { Stack<TreeNode> stack = new Stack<>(); TreeNode cur = root, last = root; // last记录上次遍历并弹出的节点 stack.push(cur); while (!stack.isEmpty()) { cur = stack.peek(); // 左子树为空,且不等于访问过的节点 if (null != cur.left && last != cur.left && last != cur.right) { stack.push(cur.left); } else if (null != cur.right && last != cur.right) { stack.push(cur.right); } else { System.out.print(stack.pop().val + " "); last = cur; } } return; } private static void postOrderTraversal2(TreeNode root) { if (null == root) { return; } Stack<TreeNode> s1 = new Stack<>(); Stack<TreeNode> s2 = new Stack<>(); TreeNode cur = root; s1.push(cur); while (!s1.isEmpty()) { cur = s1.pop(); s2.push(cur); if (null != cur.left) { s1.push(cur.left); } if (null != cur.right) { s1.push(cur.right); } } while (!s2.isEmpty()) { System.out.print(s2.pop().val + " "); } return; } // 递归构建二叉树 private static TreeNode buildTree(BufferedReader br) throws IOException { String[] rawInput = br.readLine().trim().split(" "); TreeNode root = new TreeNode(Integer.parseInt(rawInput[0])); int iLeft = Integer.parseInt(rawInput[1]); int iRight = Integer.parseInt(rawInput[2]); if (0 != iLeft) { root.left = buildTree(br); } if (0 != iRight) { root.right = buildTree(br); } return root; } } class TreeNode { int val; TreeNode left; TreeNode right; public TreeNode(int value) { this.val = value; } public TreeNode(int value, TreeNode left, TreeNode right) { this.val = value; this.left = left; this.right = right; } }
Morris遍历
import java.io.*; import java.util.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); br.readLine(); TreeNode root = createTreeNode(br); preOrderMorris(root); inOrderMorris(root); postOrderMorris(root); br.close(); } /** * Morris 遍历算法整体步骤如下(假设当前遍历到的节点为 xx): * 如果 xx 无左孩子,则访问 xx 的右孩子,即 x = x.right。 * 如果 xx 有左孩子,则找到 xx 左子树上最右的节点(即左子树中序遍历的最后一个节点,xx 在中序遍历中的前驱节点),我们记为predecessor。根据predecessor 的右孩子是否为空,进行如下操作。 * 如果 predecessor 的右孩子为空,则将其右孩子指向 xx,然后访问 xx 的左孩子,即 x = x.left。 * 如果 predecessor 的右孩子不为空,则此时其右孩子指向 xx,说明我们已经遍历完 xx 的左子树,我们将predecessor 的右孩子置空, 然后访问 xx 的右孩子,即 x = x.right。 * 作者:LeetCode-Solution * 链接:https://leetcode-cn.com/problems/recover-binary-search-tree/solution/hui-fu-er-cha-sou-suo-shu-by-leetcode-solution/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 **/ // 先序遍历 Morris遍历 莫里斯遍历 private static void preOrderMorris(TreeNode root) { if (null == root) { return; } TreeNode cur = root, predecessor = null; while (null != cur) { predecessor = cur.left; if (null != predecessor) { while (null != predecessor.right && cur != predecessor.right) { predecessor = predecessor.right; } if (null == predecessor.right) { predecessor.right = cur; System.out.print(cur.val + " "); cur = cur.left; continue; } else { predecessor.right = null; } } else { System.out.print(cur.val + " "); } cur = cur.right; } System.out.println(); } // 中序遍历 morris遍历, 复用空指针指向上层某个节点 // 这里为左子树最右结点指向根结点 private static void inOrderMorris(TreeNode root) { if (null == root) { return; } TreeNode cur = root, predecessor = null; while (null != cur) { predecessor = cur.left; if (null != predecessor) { // 获取左子树上的最右结点 while (null != predecessor.right && cur != predecessor.right) { predecessor = predecessor.right; } if (null == predecessor.right) { // 左子树上的最右结点 指向当前结点 predecessor.right = cur; cur = cur.left; continue; // 注意这里的continue; } else { // 复原空指针 predecessor.right = null; } } System.out.print(cur.val + " "); cur = cur.right; } System.out.println(); return; } // 后序遍历 morris遍历 private static void postOrderMorris(TreeNode root) { if (null == root) { return; } TreeNode cur = root, prodecessor = null; while (null != cur) { prodecessor = cur.left; if (null != prodecessor) { while (null != prodecessor.right && cur != prodecessor.right) { prodecessor = prodecessor.right; } if (null == prodecessor.right) { prodecessor.right = cur; cur = cur.left; continue; // 这里的continue; } else { prodecessor.right = null; printEdge(cur.left); } } cur = cur.right; } printEdge(root); System.out.println(); } private static void printEdge(TreeNode root) { // 逆序右边界 TreeNode tail = reverseEdge(root); TreeNode cur = tail; while (null != cur) { System.out.print(cur.val + " "); cur = cur.right; } reverseEdge(tail); } private static TreeNode reverseEdge(TreeNode from) { TreeNode next = null, pre = null; while (null != from) { next = from.right; from.right = pre; pre = from; from = next; } return pre; } private static TreeNode createTreeNode(BufferedReader br) throws IOException { String[] rawInput = br.readLine().trim().split(" "); int rootVal = Integer.parseInt(rawInput[0]); int leftVal = Integer.parseInt(rawInput[1]); int rightVal = Integer.parseInt(rawInput[2]); TreeNode root = new TreeNode(rootVal); if (0 != leftVal) { root.left = createTreeNode(br); } if (0 != rightVal) { root.right = createTreeNode(br); } return root; } } class TreeNode { int val; TreeNode left; TreeNode right; public TreeNode(int val) { this.val = val; } public TreeNode(int val, TreeNode left, TreeNode right) { this.val = val; this.left = left; this.right = right; } }
只为训练自己,时刻锤炼一个程序员最基本的技能!