相对来说,这三种代码相似度较高,而且是真正按顺序遍历,没有反转等操作。
前序遍历
前序遍历相对简单,先访问该节点,然后访问左右节点,利用栈的性质反向压入右左节点即可。
中序后序遍历
中序和后序遍历的主要思想就是先找到最左边的叶子结点,然后出栈的时候需不需要将该节点的右子树纳入考察范围,也就是说该右子树有没有被考察过(空自然不需要考察),中序遍历无需此判断,后序遍历需要,仅此而已。后序遍历就多了一个pre指针记录上一个访问的节点,也完全可以用 isVisted 属性来替代。
func preorderTraversal(_ root: TreeNode?) -> [Int] {
guard let root = root else { return [] }
let stack = ArrayStack<TreeNode>()
var result = Array<Int>()
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<TreeNode>()
var result = Array<Int>()
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<TreeNode>()
var result = Array<Int>()
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<T>: CustomStringConvertible, Stack {
private var array: Array<T>
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!
}
}
网友评论