二叉树前序中序后序遍历(迭代法,无翻转)

相对来说,这三种代码相似度较高,而且是真正按顺序遍历,没有反转等操作。

前序遍历

前序遍历相对简单,先访问该节点,然后访问左右节点,利用栈的性质反向压入右左节点即可。

中序后序遍历

中序和后序遍历的主要思想就是先找到最左边的叶子结点,然后出栈的时候需不需要将该节点的右子树纳入考察范围,也就是说该右子树有没有被考察过(空自然不需要考察),中序遍历无需此判断,后序遍历需要,仅此而已。后序遍历就多了一个pre指针记录上一个访问的节点,也完全可以用 isVisted 属性来替代。

    func preorderTraversal(_ root: TreeNode?) -> [Int] {
        guard let root = root else { return [] }
        let stack = ArrayStack()
        var result = Array()
        
        stack.push(element: root)
        while stack.isEmpty() == false {
            let nowNode = stack.pop()
            result.append(nowNode.val)
            if let right = nowNode.right {
                stack.push(element: right)
            }
            if let left = nowNode.left {
                stack.push(element: left)
            }
        }
        return result
    }
    
    func inorderTraversal(_ root: TreeNode?) -> [Int] {
        var root = root
        let stack = ArrayStack()
        var result = Array()
        
        while root != nil || stack.isEmpty() == false {
            if root != nil {
///向左走到底
                stack.push(element: root!)
                root = root?.left
            } else {
///访问该节点同时将考察节点替换为该节点右子树,叶子结点右子树为空,继续 pop,非叶子节点右子树不为空,被压入栈从而实现左中右遍历顺序
                let now = stack.pop()
                result.append(now.val)
                root = now.right
            }
        }
        
        return result
    }
    
    func postorderTraversal(_ root: TreeNode?) -> [Int] {
        var root = root
        let stack = ArrayStack()
        var result = Array()
        var pre: TreeNode? = nil
        
        while root != nil || stack.isEmpty() == false {
            if root != nil {
                stack.push(element: root!)
                root = root?.left
            } else {
                let now = stack.top()
///唯一不同,不是直接出栈,而要先判断该节点的右子树是否应该考察
                if now.right == nil || now.right === pre {
///不需要考察变走中序遍历逻辑,顺便记录下现在访问的节点。此时 root 一定为空,在栈的结构中,下一个待访问节点便是当前节点的父亲节点
                    stack.pop()
                    result.append(now.val)
                    pre = now
                } else {
///应该考察就直接赋值,重回循环
                    root = now.right
                }
            }
        }
        
        return result
    }

///自定义的数据结构
protocol Stack {
    associatedtype ItemType
    
    func getSize() -> Int
    func isEmpty() -> Bool
    func push(element: ItemType)
    func pop() -> ItemType
    func top() -> ItemType
}

class ArrayStack: CustomStringConvertible, Stack {
    private var array: Array
    
    var description: String {
        var des = "["
        for i in 0 ..< array.count {
            des += "\(array[i])"
            if i != (array.count - 1) {
                des += ", "
            }
        }
        des += "] top"
        return des
    }
    
    init(capacity: Int) {
        array = Array.init()
        array.reserveCapacity(capacity)
    }
    
    convenience init() {
        self.init(capacity: 10)
    }
    
    //MARK: - Stack
    func getSize() -> Int {
        return array.count
    }
    
    func isEmpty() -> Bool {
        return array.isEmpty
    }
    
    func push(element: T) {
        array.append(element)
    }
    
    @discardableResult func pop() -> T {
        return array.removeLast()
    }
    
    func top() -> T {
        return array.last!
    }
}

附带流程图

前序

IMG_1747.jpg

中序

IMG_1748.jpg

后序

IMG_1749.jpg

你可能感兴趣的:(二叉树前序中序后序遍历(迭代法,无翻转))