目的
刷题的时候遇到了几道二叉树的遍历,总结一些使用递归、迭代和morris算法的前序、中序和后续遍历,以及使用DFS和BFS的层序遍历算法。
leetcode题目
前序遍历 144
中序遍历 94
后序遍历 145
递归法
前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
if (root == null) return ans;
helper(ans, root);
return ans;
}
public void helper(List<Integer> ans, TreeNode node)
{
if (node == null) return;
ans.add(node.val);
if (node.left != null) helper(ans, node.left);
if (node.right != null) helper(ans, node.right);
}
}
中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
helper(ans, root);
return ans;
}
public void helper(List<Integer> ans, TreeNode root)
{
if (root != null)
{
if (root.left != null)
{
helper(ans, root.left);
}
ans.add(root.val);
if (root.right != null)
{
helper(ans, root.right);
}
}
}
}
后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
if (root == null) return ans;
helper(ans, root);
return ans;
}
public void helper(List<Integer> ans, TreeNode node)
{
if (node == null) return;
if (node.left != null) helper(ans, node.left);
if (node.right != null) helper(ans, node.right);
ans.add(node.val);
}
}
利用栈的迭代法
前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if (root == null) return ans;
stack.push(root);
while(!stack.isEmpty())
{
TreeNode node = stack.pop();
ans.add(node.val);
if (node.right != null) stack.push(node.right);
if (node.left != null) stack.push(node.left);
}
return ans;
}
}
中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
while (curr != null || !stack.isEmpty())
{
while (curr != null)
{
stack.push(curr);
curr = curr.left;
}
curr = stack.pop();
ans.add(curr.val);
curr = curr.right;
}
return ans;
}
}
后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if (root == null) return ans;
TreeNode curr = root, markNode = null;
while(!stack.isEmpty() || curr != null)
{
if (curr != null)
{
stack.push(curr);
curr = curr.left;
}
else
{
curr = stack.peek();
if (curr.right != null && markNode != curr.right)
{
stack.push(curr.right);
curr = curr.right.left;
}
else
{
curr = stack.pop();
ans.add(curr.val);
markNode = curr;
curr = null;
}
}
}
return ans;
}
}
莫里斯遍历法
前序遍历和中序遍历代码相似,只在输出的判断上有所不同。
前序遍历在找到前驱结点后,当即输出当前结点;中序遍历在判断出前序结点被输出过后,方才输出当前结点。
前序遍历
List<Integer> ans = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if (root == null) return ans;
TreeNode curr = root, predecesosor = null;
while(curr != null)
{
if (curr.left == null)
{
ans.add(curr.val);
curr = curr.right;
}
else {
predecesosor = curr.left;
while (predecesosor.right != null && predecesosor.right != curr)
{
predecesosor = predecesosor.right;
}
if (predecesosor.right == null)
{
predecesosor.right = curr;
ans.add(curr.val);
curr = curr.left;
}
if (predecesosor.right == curr)
{
predecesosor.right = null;
curr = curr.right;
}
}
}
return ans;
中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if (root == null) return ans;
TreeNode curr = root, predecesosor = null;
while(curr != null)
{
if (curr.left == null)
{
ans.add(curr.val);
curr = curr.right;
}
else {
predecesosor = curr.left;
while (predecesosor.right != null && predecesosor.right != curr)
{
predecesosor = predecesosor.right;
}
if (predecesosor.right == null)
{
predecesosor.right = curr;
curr = curr.left;
}
if (predecesosor.right == curr)
{
predecesosor.right = null;
ans.add(curr.val);
curr = curr.right;
}
}
}
return ans;
}
}
后序遍历
后序遍历需要一个dummy head作为辅助,根的左子树上的结点都与前驱结点建立联系后,在第二次访问某个结点时,逆序输出其左孩子到前驱结点的路径。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if (root == null) return ans;
TreeNode dummy = new TreeNode(0);
dummy.left = root;
TreeNode curr = root, predecesosor = null;
while(curr != null)
{
if (curr.left == null)
{
curr = curr.right;
}
else {
predecesosor = curr.left;
while (predecesosor.right != null && predecesosor.right != curr)
{
predecesosor = predecesosor.right;
}
if (predecesosor.right == null)
{
predecesosor.right = curr;
curr = curr.left;
}
if (predecesosor.right == curr)
{
predecesosor.right = null;
getEdge(ans, curr.left);
curr = curr.right;
}
}
}
getEdge(ans, root);
return ans;
}
public void getEdge(List<Integer> ans, TreeNode node)
{
TreeNode tail = Reverse(node);
TreeNode curr = tail;
while (curr != null)
{
ans.add(curr.val);
curr = curr.right;
}
Reverse(tail);
}
public TreeNode Reverse(TreeNode node)
{
TreeNode pre = null;
TreeNode next = null;
while (node != null)
{
next = node.right;
node.right = pre;
pre = node;
node = next;
}
return pre;
}
}