Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Sources/SwiftDataStructure/TempExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// File.swift
//
//
// Created by 游宗諭 on 2020/2/9.
//

import Foundation


extension CustomStringConvertible {
public func description(tabWithMax max:Int) -> String {
let MaxtabCount = (max / 4) + 1
let count = description.count
let myTabCount = MaxtabCount - (count / 4)
var resultString = description
for _ in 0..<myTabCount {
resultString += "\t"
}
return resultString
}
}
105 changes: 105 additions & 0 deletions Sources/SwiftDataStructure/Tree/BinaryTreeNode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
A general-purpose binary tree.
Nodes don't have a reference to their parent.
*/
public indirect enum BinaryTreeNode<T> {
case node(BinaryTreeNode<T>, T, BinaryTreeNode<T>)
case empty

public var count: Int {
switch self {
case let .node(left, _, right):
return left.count + 1 + right.count
case .empty:
return 0
}
}
}

extension BinaryTreeNode: CustomStringConvertible {
public var description: String {
switch self {
case let .node(left, value, right):
return "value: \(value), left = [\(left.description)], right = [\(right.description)]"
case .empty:
return ""
}
}
}

extension BinaryTreeNode {
public enum TraverseOption:CustomStringConvertible {
public var description: String {
switch self {
case .pre: return "pre"
case .in: return "in"
case .post: return "post"
}
}

case pre,`in`, post
}
public func traverse(by option:TraverseOption,
process: (T) -> Void) {
switch option {
case .pre: traversePreOrder(process: process)
case .in: traverseInOrder(process: process)
case .post: traversePostOrder(process: process)
}
}
public func traverseInOrder(process: (T) -> Void) {
if case let .node(left, value, right) = self {
left.traverseInOrder(process: process)
process(value)
right.traverseInOrder(process: process)
}
}

public func traversePreOrder(process: (T) -> Void) {
if case let .node(left, value, right) = self {
process(value)
left.traversePreOrder(process: process)
right.traversePreOrder(process: process)
}
}

public func traversePostOrder(process: (T) -> Void) {
if case let .node(left, value, right) = self {
left.traversePostOrder(process: process)
right.traversePostOrder(process: process)
process(value)
}
}
}

extension BinaryTreeNode {
func invert() -> BinaryTreeNode {
if case let .node(left, value, right) = self {
return .node(right.invert(), value, left.invert())
} else {
return .empty
}
}
}

public class BinaryTree<T> {
public init(_ node: BinaryTree<T>.Node) {
self.node = node
}

public typealias Node = BinaryTreeNode<T>
private var node: Node

public var children:(Node,Node)? {
switch node {
case .node(let r,_,let l): return (r,l)
default: return nil
}
}
public var value:T? {
switch node {
case .node(_,let v,_): return v
default: return nil
}
}
}
8 changes: 8 additions & 0 deletions Sources/SwiftDataStructure/Tree/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Tree

* a collection of nodes
* a distinguished node root
* zero or more nonempty (sub)trees
* level: height of tree(長得像大ray哥的老師在他家祖譜排level 32)
* degree: number of pointing out
* parent: 最原始的祖先
40 changes: 40 additions & 0 deletions Sources/SwiftDataStructure/Tree/Tree.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
public class TreeNode<T> {
public var value: T

public weak var parent: TreeNode?
public var children = [TreeNode<T>]()

public init(value: T) {
self.value = value
}

public func addChild(_ node: TreeNode<T>) {
children.append(node)
node.parent = self
}
}

extension TreeNode: CustomStringConvertible {
public var description: String {
var s = "\(value)"
if !children.isEmpty {
s += " {" + children.map { $0.description }.joined(separator: ", ") + "}"
}
return s
}
}

extension TreeNode where T: Equatable {
public func search(_ value: T) -> TreeNode? {
if value == self.value {
return self
}
for child in children {
if let found = child.search(value) {
return found
}
}
return nil
}
}

37 changes: 37 additions & 0 deletions Tests/SwiftDataStructureTests/TreeTests/BinaryTreeTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import XCTest
import SwiftDataStructure

class BinaryTreeTests: XCTestCase {
let node5 = BinaryTreeNode.node(.empty, "5", .empty)
let nodeA = BinaryTreeNode.node(.empty, "a", .empty)
let node10 = BinaryTreeNode.node(.empty, "10", .empty)
let node4 = BinaryTreeNode.node(.empty, "4", .empty)
let node3 = BinaryTreeNode.node(.empty, "3", .empty)
let nodeB = BinaryTreeNode.node(.empty, "b", .empty)

lazy var tree:BinaryTreeNode<String> = {
let aMinus10 = BinaryTreeNode.node(nodeA, "-", node10)
let timesLeft = BinaryTreeNode.node(node5, "*", aMinus10)

// intermediate nodes on the right
let minus4 = BinaryTreeNode.node(.empty, "-", node4)
let divide3andB = BinaryTreeNode.node(node3, "/", nodeB)
let timesRight = BinaryTreeNode.node(minus4, "*", divide3andB)
return BinaryTreeNode.node(timesLeft, "+", timesRight)
}()
// intermediate nodes on the left

// root node

func testBinaryTree() {
print(tree)
for option in [BinaryTreeNode<String>.TraverseOption.pre,.in,.post] {
print(option.description(tabWithMax: 5), terminator: "")
tree.traverse(by: option) { (str) in
print(str, separator: "", terminator: " ")
}
print()
}
}

}
78 changes: 78 additions & 0 deletions Tests/SwiftDataStructureTests/TreeTests/TreeNodeTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import XCTest
import SwiftDataStructure

class TreeNodeTESTS: XCTestCase {

let tree = TreeNode<String>(value: "beverages")

let hotNode = TreeNode<String>(value: "hot")
let coldNode = TreeNode<String>(value: "cold")

let teaNode = TreeNode<String>(value: "tea")
let coffeeNode = TreeNode<String>(value: "coffee")
let chocolateNode = TreeNode<String>(value: "cocoa")

let blackTeaNode = TreeNode<String>(value: "black")
let greenTeaNode = TreeNode<String>(value: "green")
let chaiTeaNode = TreeNode<String>(value: "chai")

let sodaNode = TreeNode<String>(value: "soda")
let milkNode = TreeNode<String>(value: "milk")

let gingerAleNode = TreeNode<String>(value: "ginger ale")
let bitterLemonNode = TreeNode<String>(value: "bitter lemon")

func testTreeNode() {
XCTAssertEqual(tree.value, "beverages")
tree.addChild(hotNode)
tree.addChild(coldNode)

hotNode.addChild(teaNode)
hotNode.addChild(coffeeNode)
hotNode.addChild(chocolateNode)

coldNode.addChild(sodaNode)
coldNode.addChild(milkNode)

teaNode.addChild(blackTeaNode)
teaNode.addChild(greenTeaNode)
teaNode.addChild(chaiTeaNode)

sodaNode.addChild(gingerAleNode)
sodaNode.addChild(bitterLemonNode)



XCTAssertNotNil(tree.search("cocoa"))
XCTAssertNotNil(tree.search("chai"))
XCTAssertNil(tree.search("bubbly"))

XCTAssertEqual(
tree.description,
"""
beverages \
{hot\
{tea\
{black, green, chai},\
coffee, cocoa},\
cold\
{soda\
{ginger ale, bitter lemon},\
milk}\
}
""")
}
}
extension TreeNode where T: Equatable {
func search(_ value: T) -> TreeNode? {
if value == self.value {
return self
}
for child in children {
if let found = child.search(value) {
return found
}
}
return nil
}
}