樹節點的定義
首先,給出樹節點的定義,方便我們理解下面的算法:
public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x) {
val = x;
}
}
如上述代碼所示,二叉樹節點定義爲TreeNode
,其中
val
,表示當前節點的值;left
,表示當前節點的左兒子節點;right
,表示當前節點的右兒子節點。
二叉樹的前序遍歷
給定一個二叉樹,返回它的前序遍歷。
示例:
輸入: [1,null,2,3]
1
\
2
/
3
輸出: [1,2,3]
如上述所示,前序遍歷的順序爲:根節點、左子樹和右子樹。
遞歸
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
helper(root, ans);
return ans;
}
private void helper(TreeNode node, List<Integer> ans) {
if (node != null) {
ans.add(node.val);
if (node.left != null) {
helper(node.left, ans);
}
if (node.right != null) {
helper(node.right, ans);
}
}
}
}
迭代
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
if (root == null) return ans;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode curr = stack.pop();
ans.add(curr.val);
if (curr.right != null) {
stack.push(curr.right);
}
if (curr.left != null) {
stack.push(curr.left);
}
}
return ans;
}
}
二叉樹的中序遍歷
給定一個二叉樹,返回它的中序遍歷。
示例:
輸入: [1,null,2,3]
1
\
2
/
3
輸出: [1,3,2]
如上述所示,中序遍歷的順序爲:左子樹、根節點和右子樹。
遞歸
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
helper(root, ans);
return ans;
}
private void helper(TreeNode node, List<Integer> ans) {
if (node != null) {
if (node.left != null) {
helper(node.left, ans);
}
ans.add(node.val);
if (node.right != null) {
helper(node.right, 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;
}
}
二叉樹的後序遍歷
給定一個二叉樹,返回它的後序遍歷。
示例:
輸入: [1,null,2,3]
1
\
2
/
3
輸出: [3,2,1]
如上述所示,後序遍歷的順序爲:左子樹、右子樹和根節點。
遞歸
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
helper(root, ans);
return ans;
}
private void helper(TreeNode node, List<Integer> ans) {
if (node != null) {
if (node.left != null) {
helper(node.left, ans);
}
if (node.right != null) {
helper(node.right, ans);
}
ans.add(node.val);
}
}
}
迭代
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<Integer> ans = new LinkedList<>();
if (root == null) return ans;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode curr = stack.pop();
ans.addFirst(curr.val);
if (curr.left != null) {
stack.push(curr.left);
}
if (curr.right != null) {
stack.push(curr.right);
}
}
return ans;
}
}
二叉樹的層序遍歷
給你一個二叉樹,請你返回其按層序遍歷得到的節點值。
示例:
二叉樹:[3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其層次遍歷結果:
[
[3],
[9,20],
[15,7]
]
如上述所示,層序遍歷的順序爲:逐層地,從左到右訪問所有節點
遞歸
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ans = new ArrayList<>();
if (root == null) return ans;
helper(root, ans, 0);
return ans;
}
private void helper(TreeNode node, List<List<Integer>> ans, int level) {
if (ans.size() == level) {
ans.add(new ArrayList<>());
}
ans.get(level).add(node.val);
if (node.left != null) {
helper(node.left, ans, level + 1);
}
if (node.right != null) {
helper(node.right, ans, level + 1);
}
}
}
迭代
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ans = new ArrayList<>();
if (root == null) return ans;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
int level = 0;
while (!queue.isEmpty()) {
ans.add(new ArrayList<>());
int levelLength = queue.size();
for (int i = 0; i < levelLength; ++i) {
TreeNode node = queue.remove();
ans.get(level).add(node.val);
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
level++;
}
return ans;
}
}
二叉樹的蛇形遍歷
給定一個二叉樹,返回其節點值的蛇形層次遍歷,蛇形層次遍歷也稱爲鋸齒形層次遍歷。
例如:
給定二叉樹 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回蛇形層次遍歷如下:
[
[3],
[20,9],
[15,7]
]
如上述所示,蛇形層次遍歷的順序爲:先從左往右,再從右往左進行下一層遍歷,以此類推,層與層之間交替進行。
遞歸
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> ans = new ArrayList<>();
helper(root, ans, 0);
return ans;
}
private void helper(TreeNode node, List<List<Integer>> ans, int level) {
if (node == null) return;
if (ans.size() <= level) {
List<Integer> newLevel = new LinkedList<>();
ans.add(newLevel);
}
List<Integer> collection = ans.get(level);
if (level % 2 == 0) {
collection.add(node.val);
} else {
collection.add(0, node.val);
}
helper(node.left, ans, level + 1);
helper(node.right, ans, level + 1);
}
}
迭代
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> ans = new ArrayList<>();
if (root == null) return ans;
LinkedList<TreeNode> nodeQueue = new LinkedList<>();
nodeQueue.addLast(root);
nodeQueue.addLast(null);
LinkedList<Integer> levelList = new LinkedList<>();
boolean isOrderLeft = true;
while (nodeQueue.size() > 0) {
TreeNode currNode = nodeQueue.pollFirst();
if (currNode != null) {
if (isOrderLeft) {
levelList.addLast(currNode.val);
} else {
levelList.addFirst(currNode.val);
}
if (currNode.left != null) {
nodeQueue.addLast(currNode.left);
}
if (currNode.right != null) {
nodeQueue.addLast(currNode.right);
}
} else {
ans.add(levelList);
levelList = new LinkedList<>();
if (nodeQueue.size() > 0) {
nodeQueue.addLast(null);
}
isOrderLeft = !isOrderLeft;
}
}
return ans;
}
}
總結
如上述內容所示,對於二叉樹的各種遍歷形式,我們都給出了兩種實現方式,分別爲:
- 遞歸
- 迭代
其中,遞歸實現較爲容易,但迭代實現卻有些難度。仔細分析代碼,我們會發現:
- 在遞歸實現中,我們一般需要藉助
helper
函數來實現遞歸的形式; - 在迭代實現中,我們一般需要藉助
Stack
或Queue
的特性來實現特殊的存儲需求。
雖然遞歸實現相對簡單,但因爲遞歸存在着各種各樣的問題,所以我們一般不建議使用遞歸操作,具體可以參考:
這篇博文。到此,本文就結束了,歡迎大家留言討論!