二叉樹的先序、中序、後序遍歷,包括遞歸方式和非遞歸方式
1、二叉樹的前序遍歷
1.1 思路:
二叉樹是一個由left子節點和right子節點 以及val組成的數據結果。而前序遍歷的過程就是 根左右。
而實現前序遍歷,我們可以用兩種方式一種是遞歸實現,先添加val,遞歸左右子節點。一種非遞歸實現,
遞歸的實現就是系統幫我們自行壓棧操作,因此可以藉助棧結構來實現。先添加root節點,當棧不爲null 保存root.val 以及壓入左子節點和右子節點。如此反覆。
時間複雜度:二叉樹的遍歷需要花費O(n) 如果不計算棧的消耗
空間複雜度:O(n) 無論是遞歸還是非遞歸 都需要進行O(n)
1.2 遞歸實現 code
//棧
public List<Integer> preorderTraversal(TreeNode root) {
ArrayList<Integer> res = new ArrayList<>();
if(root == null) return res;
Stack<TreeNode> stack = new Stack();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
res.add(node.val);
if(node.right!=null){
stack.push(node.right);
}
if(node.left != null){
stack.push(node.left);
}
}
return res;
}
1.3 非遞歸實現 code
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
res.add(node.val);
if(node.right != null){
stack.push(node.right);
}
if(node.left != null){
stack.push(node.left);
}
}
return res;
}
2、二叉樹的中序遍歷
2.1 思路:
中序遍歷和前序遍歷的遞歸版相似,只需要修改添加的位置。
而非遞歸版藉助棧 先壓入左子節點,如果左子節點爲null 彈出 添加值,然後查看右子節點。
時間複雜度:O(n)
空間複雜度:O(n)
2.2 遞歸實現 code
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList();
helper(root,result);
return result;
}
public static void helper(TreeNode root,List<Integer> result){
if(root!=null){
//左
if(root.left!=null){
helper(root.left,result);
}
//中
result.add(root.val);
//右
if(root.right!=null){
helper(root.right,result);
}
}
}
2.3 非遞歸實現 code
//藉助stack
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null) return res;
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while( cur!=null || !stack.empty()){
//添加左節點
while(cur!=null){
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
res.add(cur.val);
//push右節點
cur = cur.right;
}
return res;
}
3、二叉樹的後序遍歷
3.1 思路:
遞歸版 直接 修改add的位置
非遞歸版 後序遍歷 爲 左右根 而前序遍歷爲根左右 有沒有發現 如果將左右的位置改變 然後在逆序就是後序遍歷的結果了。這裏藉助兩個棧。一個棧存儲節點,另一個棧存儲數據,將根右左的值添加 然後pop 就是結果。
時間複雜度:O(n)
空間複雜度:O(n)
3.2 遞歸實現 code
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null) return res;
helper(root,res);
return res;
}
public void helper(TreeNode node,List<Integer> res){
if(node!=null){
if(node.left!=null){
helper(node.left,res);
}
if(node.right!=null){
helper(node.right,res);
}
res.add(node.val);
}
}
3.3 非遞歸實現 code
//左右根 先序遍歷 根左右 根右左
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root==null) return res;
Stack<Integer> stack = new Stack();//存儲數據
Stack<TreeNode> nodeStack = new Stack();//存儲節點
nodeStack.push(root); //先存儲根節點
while(!nodeStack.isEmpty()){
TreeNode node = nodeStack.pop();
stack.push(node.val);
if(node.left!=null){
nodeStack.push(node.left);
}
if(node.right!=null){
nodeStack.push(node.right);
}
}
while(!stack.isEmpty()){
res.add(stack.pop());
}
return res;
}