JAVA實現二叉樹、N叉樹遞歸/非遞歸實現前、中、後序遍歷

在寫劍指offer和LeetCode算法時,遇到了有關二叉樹前中後序遍歷的題目,之前一直使用遞歸寫法,導致對非遞歸寫法有點生疏了,在此記錄一下。對於非遞歸寫法,通常都是藉助棧或隊列等數據結構,在實現過程中一定要時刻牢記棧(先進後出)、隊列(先進先出)等特性。再就是前(根左右)中(左根右)後(左右根)序遍歷。

題目解答中用到的TreeNode類,定義如下:

public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

遞歸實現二叉樹的前-中-後序遍歷

//前序
public void preOrder(TreeNode node)
    {
        if (node != null)
        {
            System.out.print(node.element + " ");
            preOrder(node.left);
            preOrder(node.right);
        }
    }
//中序
public void inOrder(TreeNode node)
    {
        if (node != null)
        {   
            preOrder(node.left);
            System.out.print(node.element + " ");
            preOrder(node.right);
        }
    }
//後序:
public void posOrder(TreeNode node)
    {
        if (node != null)
        {            
            preOrder(node.left);
            preOrder(node.right);
            System.out.print(node.element + " ");
        }
    }

非遞歸實現二叉樹的前-中-後序遍歷

//前序:藉助一個棧
public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null){
            return res;
        }
        Stack<TreeNode> s = new Stack<>();
       s.push(root);
       while (!s.empty()){
           TreeNode node = s.pop();
           res.add(node.val);
           if (node.right != null){
               s.push(node.right);
           }
           if (node.left != null){
               s.push(node.left);
           }
       }
       return res;
    }
//=========================================
//前序遍歷2
public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null){
            return res;
        }
        Stack<TreeNode> s = new Stack<>();
       while (root != null || !s.empty()){
           while(root != null){
               res.add(root.val);
               s.push(root);
               root = root.left;
           }
           if(!s.empty()){
               TreeNode t = s.pop();
               root = t.right;
           }
       }
       return res;
    }
//中序:藉助一個棧
 public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null){
            return res;
        }
        Stack<TreeNode> s = new Stack<>();
     //循環1 2步驟直至棧爲空且指針也爲空
        while (root != null || !s.empty()){
            //1.不斷往左子樹深入並不斷入棧,直到左葉子的空左孩子
            while (root != null){
                s.push(root);
                root = root.left;
            }
            //2.彈出棧頂元素,將值加入res,並將指針指向它的右孩子
            if (!s.empty()){
                root = s.pop();
                res.add(root.val);
                root = root.right;
            }
        }

        return res;
    }
//後序:後序遍歷是 左右根,從右往左依次是根右左,先序遍歷是根左右,考慮修改先序遍歷之後再調整順序。
public List<Integer> postorderTraversal(TreeNode root) {
        LinkedList<Integer> res = new LinkedList<>();
        if (root == null){
            return res;
        }
        Stack<TreeNode> s = new Stack<>();
        s.push(root);
        TreeNode node = null;
        while (!s.isEmpty()){
            node = s.pop();
            //注意使用的是頭插法,這樣的話實現逆序的過程
            res.addFirst(node.val);
            //根據棧 先進後出的特點,根右左,那麼入棧的時候用先左再右
            if (node.left != null){
                s.push(node.left);
            }
            if (node.right != null){
                s.push(node.right);
            }
        }
        return res;
    }


N叉樹的定義

class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
}

N叉樹前、後序遍歷的遞歸實現

//前序
 public List<Integer> preorder(Node root) {
        List<Integer> res = new ArrayList<>();
        preOrderNT(root,res);
        return res;
    }

    private void preOrderNT(Node node, List<Integer> res) {
        if (node == null){
            return;
        }
        res.add(node.val);
        if (node.children.size() >0){
            for (Node _node:node.children) {
                preOrderNT(_node,res);
            }
        }
    }

//後序
 public List<Integer> postorder(Node root) {
        List<Integer> res = new ArrayList<>();
        postOrderNT(root,res);
        return res;
    }

    private void postOrderNT(Node node, List<Integer> res) {
        if (node == null){
            return;
        }
        if (node.children != null && node.children.size() > 0){
            for (Node _node:node.children) {
                postOrderNT(_node,res);
            }
        }
        res.add(node.val);
    }

N叉樹前、後序遍歷的非遞歸實現

//前序
public List<Integer> preorder(Node root) {
       List<Integer> res = new ArrayList<>();
        if (root == null){
            return res;
        }
        Stack<Node> s = new Stack<>();
        s.push(root);
        Node temp = null;
        while (!s.isEmpty()){
            temp = s.pop();
            res.add(temp.val);
            if (temp.children.size() >0){
                for (int i = temp.children.size() -1;i>=0;i--){
                    //從右往左依次入棧
                   if (temp.children != null){
                       s.push(temp.children.get(i));
                   }
                }
            }
        }
        return res; 
    }

//後序
public List<Integer> postorder(Node root) {
	List<Integer> res = new ArrayList<>();
        if (root == null){
            return res;
        }
        Stack<Node> s = new Stack<>();
        s.push(root);
        Node temp = null;
        while (!s.isEmpty()){
            temp = s.pop();
            res.add(temp.val);
            if (temp.children.size() >0){
                for (Node _node:temp.children) {
                    s.push(_node);
                }
            }
        }
		//將res求逆,得到最後的結果
        Collections.reverse(res);
        return res; 
 }

java.util.Collections類中的reverse方法

private static final int REVERSE_THRESHOLD        =   18;
public static void reverse(List<?> list) {
        int size = list.size();
        if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
                swap(list, i, j);
        } else {
            // instead of using a raw type here, it's possible to capture
            // the wildcard but it will require a call to a supplementary
            // private method
            ListIterator fwd = list.listIterator();
            ListIterator rev = list.listIterator(size);
            for (int i=0, mid=list.size()>>1; i<mid; i++) {
                Object tmp = fwd.next();
                fwd.set(rev.previous());
                rev.set(tmp);
            }
        }
    }

public static void swap(List<?> list, int i, int j) {
        // instead of using a raw type here, it's possible to capture
        // the wildcard but it will require a call to a supplementary
        // private method
        final List l = list;
        l.set(i, l.set(j, l.get(i)));
    }

java.util.List接口
interface List<E> extends Collection<E>

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