樹 先序遍歷 中序遍歷 後序遍歷

 寫之前先看作用:

先序遍歷:在第一次遍歷到節點時就執行操作,一般只是想遍歷執行操作(或輸出結果)可選用先序遍歷;
中序遍歷:對於二分搜索樹,中序遍歷的操作順序(或輸出結果順序)是符合從小到大(或從大到小)順序的,故要遍歷輸出排序好的結果需要使用中序遍歷
後序遍歷:後續遍歷的特點是執行操作時,肯定已經遍歷過該節點的左右子節點,故適用於要進行破壞性操作的情況,比如刪除所有節點

 

先序:中 左 右的順序(先訪問根節點,先序遍歷左子樹,先序遍歷右子樹

中序:左 中 右的順序

後序:左 右 中的順序

遍歷過程相同,只是訪問各個節點的時機不同

 

先序遍歷

 

 遞歸實現:

    public static void preOrderRecur(TreeNode treeNode)
    {
        if (treeNode==null)
        {
            return;
        }
        System.out.println(treeNode.val);
        preOrderRecur(treeNode.left);
        preOrderRecur(treeNode.right);
    }

夠簡單,需要注意終止條件。否則會空指針異常。

 

非遞歸實現(自己維護一個棧):

public static void preOrder(TreeNode treeNode)
    {
        if(treeNode==null)
        {
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();//注意泛型
        stack.push(treeNode);
        while (stack.size()!=0)
        {
            treeNode=stack.pop();
            System.out.println(treeNode.val + " ");
            if(treeNode.right!=null)//注意不爲null的條件,否則出棧會空指針
            {
                stack.push(treeNode.right);//由於先處理左子樹,後處理右子樹,所以壓棧順序反過來就行
            }
            if(treeNode.left!=null)
            {
                stack.push(treeNode.left);
            }

        }
    }

這個迭代寫的有點像遞歸了。。。

 

中序遍歷

 

 

 

遞歸寫法,真的爽,不用考慮具體的壓棧過程,關注什麼時候結束和遞歸邏輯就行

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        parse(root,list); 
        return list;       
    }

    public void parse(TreeNode root,List<Integer> list)
    {
        if(root==null)
        {
            return;
        }
        parse(root.left,list);
        list.add(root.val);
        parse(root.right,list);
    }
}

 

非遞歸寫法:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        Stack<TreeNode> stack=new Stack<>();
        List<Integer> list=new ArrayList<>();
        while(stack.size()>0||root!=null)
        {
            while(root!=null)//處理root節點,去往最左側,出循環後棧頂爲優先級最高節點
            {
                stack.push(root);
                root=root.left;
            }
            TreeNode outNode=stack.pop();//到這裏保證左側已經沒有東西了,outnode代表目前全樹優先級最高的節點
            list.add(outNode.val);//處理“中”
            if(outNode.right!=null)//處理“右”,這一步加上去往最左能保證右子樹被處理完
            {
                root=outNode.right;
            }
        } 
        return list;
    }   
}
  • root是要處理的節點,當root不爲null時,還沒有找到最高優先級的節點,當root爲null時,最高優先級節點在棧頂,且這個最高優先級節點的父親在棧的第二位
  • 處理最高優先級節點的辦法是,彈出棧,輸出最高優先級節點,處理右子樹(即把root設置爲其右孩子)
  • 還是有點繞的。。。

 

後序遍歷

 

 

遞歸寫法,差不多

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        postOrder(root,list);
        return list;
    }

    public void postOrder(TreeNode root,List<Integer> list)
    {
        if(root==null)
        {return;}
        postOrder(root.left,list);
        postOrder(root.right,list);
        list.add(root.val);
    }
}

非遞歸寫法有兩種

第一種:雙棧法,前序遍歷不是中左右,改變一下壓棧順序就成了中右左,倒序過來就是左右中。

倒序使用第二個棧就能實現,記錄下來出棧的節點就可以

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        if(root==null)
        {return list;}
        Stack<TreeNode> stackReverse=new Stack<TreeNode>();
        Stack<TreeNode> stackResult=new Stack<TreeNode>();
        stackReverse.push(root);
        while(stackReverse.size()>0)
        {
            root=stackReverse.pop();
            stackResult.add(root);
            if(root.left!=null)
            {stackReverse.push(root.left);}
            if(root.right!=null)
            {stackReverse.push(root.right);}
        }
        while(stackResult.size()>0)
        {
            list.add(stackResult.pop().val);
        }
        return list;
    }
}

 第二種,硬寫唄

和中序遍歷有點像,先要找優先級最高的節點root,往左探

當root爲null時,cur=stack.pop,但是此時優先級更高的不是cur而是cur.right

所以加入cur.right不爲null,肯定要先處理右側節點,cur要先放回棧

爲了到時右側節點被處理完了,cur再出棧時能知道,所以加了一個pre(因爲cur.right處理完肯定下一個就是cur)

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        if(root==null)
        {return list;}
        Stack<TreeNode> stack=new Stack<TreeNode>();
        TreeNode pre=null;
        while(stack.size()>0||root!=null)
        {
            while(root!=null)
            {
                stack.push(root);
                root=root.left;
            }
            TreeNode cur=stack.pop();
            if(cur.right==null||pre==cur.right)
            {
                list.add(cur.val);
                pre=cur;
            }
            else
            {
                stack.push(cur);
                root=cur.right;
            }
        }
        return list;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章