二叉树的定义
public class TreeNode {
public var val: Int
public var left: TreeNode?
public var right: TreeNode?
public init(_ val: Int) {
self.val = val
self.left = nil
self.right = nil
}
}
二叉树的比较
二叉树相等
比较两个二叉树是否相等在二叉树的操作中也是很常用的函数,主要思路也是使用回溯的思路,对二叉树的节点逐个比较,代码如下:
func isSameTree(_ p: TreeNode?, _ q: TreeNode?) -> Bool {
if p == nil && q == nil {
return true
}
if p != nil && q != nil && p?.val == q?.val {
return isSameTree(p?.left, q?.left) && isSameTree(p?.right, q?.right)
} else {
return false
}
}
对称二叉树判定
func isSymmetric(_ root: TreeNode?) -> Bool {
return isMirror(root, t2: root)
}
func isMirror(_ t1: TreeNode?, t2: TreeNode?) -> Bool {
if t1 == nil && t2 == nil {
return true
}
if t1 == nil || t2 == nil {
return false
}
return t1?.val == t2?.val && isMirror(t1?.right, t2: t2?.left) && isMirror(t1?.left, t2: t2?.right)
}
二叉树的最大深度
func maxDepth(_ root: TreeNode?) -> Int {
if root == nil {
return 0
}
let leftHeight = maxDepth(root?.left)
let rightHeigh = maxDepth(root?.right)
return max(leftHeight, rightHeigh) + 1
}
二叉树最小深度
// 二叉树最小深度
func minDepth(_ root: TreeNode?) -> Int {
if root == nil {
return 0
}
let leftH = minDepth(root?.left)
let rightH = minDepth(root?.right)
if leftH != 0 && rightH != 0 {
return min(leftH, rightH) + 1
} else {
return leftH + rightH + 1
}
}
二叉树路径综合
// 路径总和
func hasPathSum(_ root: TreeNode?, _ sum: Int) -> Bool {
if root == nil {
return false
}
if root?.left == nil && root?.right == nil && root?.val == sum {
return true
}
return hasPathSum(root?.left, sum - root!.val) || hasPathSum(root?.right, sum - root!.val)
}
平衡二叉树判断
// 平衡二叉树
func isBalanced(_ root: TreeNode?) -> Bool {
return dfsHeight(root) != -1
}
func dfsHeight(_ root: TreeNode?) -> Int {
if root == nil {
return 0
}
let leftHeight = dfsHeight(root?.left)
if leftHeight == -1 {
return -1
}
let rightHeight = dfsHeight(root?.right)
if rightHeight == -1 {
return -1
}
if abs(leftHeight - rightHeight) > 1 {
return -1
}
return max(leftHeight, rightHeight) + 1
}
二叉查找树(BST)
BST(binary sort tree)叫做二叉查找树,或者二叉排序树。BST满足一下三个条件:
- 节点的左子树包含的节点的值小于该节点的值
- 节点的右子树包含的节点的值大于等于该节点的值
- 节点的左子树和右子树都是BST
- 中序遍历可以得到一个递增序列
判断二叉树是否是BST
func isValidBST(root: TreeNode?) -> Bool {
return _helper(node: root, nil, nil)
}
func _helper(node: TreeNode?, _ min: Int?, _ max: Int?) -> Bool {
guard let node = node else {
return true
}
if let min = min, node.val <= min {
return false
}
if let max = max, node.val >= max {
return false
}
return _helper(node: node.left, min, node.val) && _helper(node: node.right, node.val, max)
}
定义二叉查找树
public class BinarySearchTree<T: Comparable> {
private(set) public var value: T
private(set) public var parent: BinarySearchTree?
private(set) public var left: BinarySearchTree?
private(set) public var right: BinarySearchTree?
public init(value: T) {
self.value = value
}
/// 是否是根节点
public var isRoot: Bool {
return parent == nil
}
/// 是否是叶节点
public var isLeaf: Bool {
return left == nil && right == nil
}
/// 是否是左子节点
public var isLeftChild: Bool {
return parent?.left === self
}
/// 是否是右子节点
public var isRightChild: Bool {
return parent?.right === self
}
/// 是否有左子节点
public var hasLeftChild: Bool {
return left != nil
}
/// 是否有右子节点
public var hasRightChild: Bool {
return right != nil
}
/// 是否有子节点
public var hasAnyChild: Bool {
return hasLeftChild || hasRightChild
}
/// 是否左右两个子节点都有
public var hasBothChildren: Bool {
return hasLeftChild && hasRightChild
}
/// 当前节点包括子树中的所有节点总数
public var count: Int {
return (left?.count ?? 0) + 1 + (right?.count ?? 0)
}
}
基本操作
插入新节点
执行插入时,我们首先将新值与根节点进行比较。 如果新值较小,我们采取左分支; 如果更大,我们采取右分支。我们沿着这条路向下走,直到找到一个我们可以插入新值的空位。
public func insert(value: T) {
if value < self.value {
if let left = left {
left.insert(value: value)
} else {
left = BinarySearchTree(value: value)
left?.parent = self
}
} else {
if let right = right {
right.insert(value: value)
} else {
right = BinarySearchTree(value: value)
right?.parent = self
}
}
}
BST的创建
以数组的方式创建二叉查找数:
public convenience init(array: [T]) {
precondition(array.count > 0)
self.init(value: array.first!)
for v in array.dropFirst() {
insert(value: v)
}
}
搜索二叉查找树
- 如果该值小于当前节点,则选择左分支。
- 如果该值大于当前节点,则选择右分支。
- 如果该值等于当前节点,我们就找到了它!
public func search(value: T) -> BinarySearchTree? {
if value < self.value {
return left?.search(value)
} else if value > self.value {
return right?.search(value)
} else {
return self // found it!
}
}
遍历二叉查找树
遍历二叉树有三种方法:
- 中序(或 深度优先,In-order/depth-first):首先查看节点的左子节点,然后查看节点本身,最后查看其右子节点。
- 前序(Pre-order):首先查看节点本身,然后查看其左右子节点。
- 后序(Post-order):首先查看左右子节点并最后处理节点本身。
遍历树的过程也是递归的,如果按 中序遍历 二叉搜索树,它会查看所有节点,并且结果是 有序 的。
//中序遍历
public func traverseInOrder(process: (T) -> Void) {
left?.traverseInOrder(process: process)
process(value)
right?.traverseInOrder(process: process)
}
//前序遍历
public func traversePreOrder(process: (T) -> Void) {
process(value)
left?.traversePreOrder(process: process)
right?.traversePreOrder(process: process)
}
//后序遍历
public func traversePostOrder(process: (T) -> Void) {
left?.traversePostOrder(process: process)
right?.traversePostOrder(process: process)
process(value)
}
删除节点
删除二叉查找树节点后,需要将节点替换为左侧最大的子节点或右侧的最小子节点。
//移除一个节点
@discardableResult public func remove() -> BinarySearchTree? {
let replacement: BinarySearchTree?
// 当前节点的替换可以是左侧最大的替换 或者
// 右边最小的那个
if let right = right {
replacement = right.minimum()
} else if let left = left {
replacement = left.maximum()
} else {
replacement = nil
}
replacement?.remove()
// 将替换放置在当前节点的位置
replacement?.right = right
replacement?.left = left
right?.parent = replacement
left?.parent = replacement
reconnectParentTo(node:replacement)
// 当前节点不再是树的一部分,因此请清理它。
parent = nil
left = nil
right = nil
return replacement
}
//重新设置一个节点
private func reconnectParentTo(node: BinarySearchTree?) {
if let parent = parent {
if isLeftChild {
parent.left = node
} else {
parent.right = node
}
}
node?.parent = parent
}
将有序数组转换为二叉查找树
public func sortedArrayToBST(_ nums: [Int]) -> BinarySearchTree<Int>? {
if nums.isEmpty {
return nil
}
return sortedArrayToBSTFunc(nums, l: 0, r: nums.count-1)
}
// 将有序数组转换为二叉查找树
private func sortedArrayToBSTFunc(_ nums: [Int], l: Int, r: Int) -> BinarySearchTree<Int>? {
if r < l {
return nil
}
let mid = l + (r - l) / 2
let root = BinarySearchTree<Int>(value: nums[mid])
root.left = sortedArrayToBSTFunc(nums, l: l, r: mid-1)
root.right = sortedArrayToBSTFunc(nums, l: mid+1, r: r)
return root
}