├── .gitignore ├── Example ├── AppDelegate.swift ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist └── ViewController.swift ├── License.md ├── README.md ├── Source ├── Extensions │ ├── Array.swift │ ├── Chain.swift │ ├── Double.swift │ ├── Int.swift │ ├── Keyable.swift │ ├── Sortable.swift │ ├── String.swift │ └── XCTestCase.swift ├── Factories │ ├── BSTree.swift │ ├── Blockchain.swift │ ├── EnumModel.swift │ ├── Graph.swift │ ├── HashTable.swift │ ├── Heap.swift │ ├── Learning.swift │ ├── LinkedList.swift │ ├── NaiveBayes.swift │ ├── PathHeap.swift │ ├── Queue.swift │ ├── Quicksort.swift │ ├── Sorting.swift │ ├── Stack.swift │ ├── Trie.swift │ └── delegation.swift ├── Models │ └── AEClassifier.mlmodel ├── Patterns │ ├── Dispatch.swift │ ├── Model.swift │ ├── ModelDelegate.swift │ └── ModelEngine.swift └── Structures │ ├── Archive │ └── BSRecursive.swift │ ├── BSNode.swift │ ├── BayesResult.swift │ ├── Block.swift │ ├── Edge.swift │ ├── Exchange.swift │ ├── IEngine.swift │ ├── LLNode.swift │ ├── Node.swift │ ├── Path.swift │ ├── Peer.swift │ ├── Protocols.swift │ ├── TrieNode.swift │ ├── Vertex.swift │ └── enums.swift ├── SwiftStructures.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── SwiftStructures.xccheckout │ └── xcuserdata │ │ └── waynebishop.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── waynebishop.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── SwiftStructures.xcscheme │ └── xcschememanagement.plist └── SwiftTests ├── BSTest.swift ├── BayesTest.swift ├── BlockTest.swift ├── ClosureTest.swift ├── DelegateTest.swift ├── FibTest.swift ├── GraphTest.swift ├── HashTest.swift ├── HeapTest.swift ├── Info.plist ├── LearningTest.swift ├── LinkedTest.swift ├── QueueTest.swift ├── QuickTest.swift ├── SortingTest.swift ├── StackTest.swift ├── StructureTest.swift ├── TrieTest.swift └── enumTest.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | .DS_Store 4 | build/ 5 | .pbxuser 6 | !default.pbxuser 7 | .mode1v3 8 | !default.mode1v3 9 | .mode2v3 10 | !default.mode2v3 11 | .perspectivev3 12 | !default.perspectivev3 13 | xcuserdata 14 | .xccheckout 15 | .moved-aside 16 | DerivedData 17 | .hmap 18 | .ipa 19 | .xcuserstate 20 | 21 | # CocoaPods 22 | # 23 | # We recommend against adding the Pods directory to your .gitignore. However 24 | # you should judge for yourself, the pros and cons are mentioned at: 25 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 26 | # 27 | # Pods/ 28 | -------------------------------------------------------------------------------- /Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/13/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/13/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | } 17 | 18 | override func didReceiveMemoryWarning() { 19 | super.didReceiveMemoryWarning() 20 | // Dispose of any resources that can be recreated. 21 | } 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015, Wayne Bishop & Arbutus Software Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Swift Structures 2 | ==================== 3 | 4 | This project provides a framework for commonly used data structures and algorithms written in a new iOS development language called Swift. While details of many algorithms exists on Wikipedia, these implementations are often written as pseudocode, or are expressed in C or C++. With Swift now officially released, its general syntax should be familiar enough for most programmers to understand. 5 | 6 | 7 | Audience 8 | --------------------- 9 | 10 | As a developer, you should already be familiar with the basics of programming. Beyond algorithms, this project also aims to provide an alternative for learning the basics of Swift. This includes implementations of many Swift-specific features such as optionals, extensions, protocols and generics. Beyond Swift, audiences should be familiar with **Singleton** and **Factory** design patterns along with sets, arrays and dictionaries. 11 | 12 | 13 | Features 14 | -------------------- 15 | 16 | The project features code-level examples for the following items: 17 | 18 | + [Linked Lists](/Source/Factories/LinkedList.swift) 19 | + [Binary Search](/Source/Extensions/Array.swift) 20 | + [Insertion Sort](/Source/Extensions/Array.swift) 21 | + [Bubble Sort](/Source/Extensions/Array.swift) 22 | + [Selection Sort](/Source/Extensions/Array.swift) 23 | + [Quick Sort](/Source/Extensions/Array.swift) 24 | + [Binary Search Trees](/Source/Factories/BSTree.swift) 25 | + [Tree Balancing - Rotations](/Source/Factories/BSTree.swift) 26 | + [Stacks](/Source/Factories/Stack.swift) 27 | + [Queues](/Source/Factories/Queue.swift) 28 | + [Heaps & Heapsort Operations](/Source/Factories/Heap.swift) 29 | + [Hash Tables](/Source/Factories/Hashtable.swift) 30 | + [Tries](/Source/Factories/Trie.swift) 31 | + [Graphs](/Source/Factories/Graph.swift) 32 | + [Dijkstra's Shortest Path](/Source/Factories/Graph.swift) 33 | + [Depth-First Search](/Source/Structures/BSNode.swift) 34 | + [Breadth-First Search](/Source/Factories/Graph.swift) 35 | + [Protocol Extensions](/Source/Extensions/Sortable.swift) 36 | + [Enumerations](/Factories/enumModel.swift) 37 | + [Fibonacci Numbers](/Source/Extensions/Int.swift) 38 | + Generics 39 | + Dyanmic Programming 40 | + [Closures](/SwiftTests/ClosureTest.swift) 41 | 42 | 43 | 44 | The Book 45 | -------------------- 46 | Now in its **4th edition** and supporting **Swift 4.2**, the The Swift Algorithms Book features code and color illustrations that benefits students and professionals. As a collaborative open-source effort, I also welcome feedback and contribution from others. 47 | 48 | 49 | Example 50 | -------------------- 51 | 52 | ```swift 53 | //bfs traversal with inout closure function 54 | func traverse(_ startingv: Vertex, formula: (_ node: inout Vertex) -> ()) { 55 | 56 | 57 | //establish a new queue 58 | let graphQueue: Queue = Queue() 59 | 60 | 61 | //queue a starting vertex 62 | graphQueue.enQueue(startingv) 63 | 64 | 65 | while !graphQueue.isEmpty() { 66 | 67 | 68 | //traverse the next queued vertex - Swift 4.0 69 | //var vitem: Vertex! = graphQueue.deQueue() 70 | 71 | 72 | //traverse the next queued vertex 73 | guard var vitem = graphQueue.deQueue() else { 74 | break 75 | } 76 | 77 | //add unvisited vertices to the queue 78 | for e in vitem.neighbors { 79 | if e.neighbor.visited == false { 80 | print("adding vertex: \(e.neighbor.key) to queue..") 81 | graphQueue.enQueue(e.neighbor) 82 | } 83 | } 84 | 85 | //invoke formula 86 | formula(&vitem) 87 | 88 | 89 | } //end while 90 | 91 | 92 | print("graph traversal complete..") 93 | 94 | } 95 | ``` 96 | 97 | Getting Started 98 | -------------------- 99 | 100 | Swift Structures has been optimized for **Swift 4.2** (e.g., Xcode 10.0) or later. The directories are organized as follows: 101 | + Source - Code for all Swift data structures, algorithms and source extensions 102 | + Example - An empty iOS single-view application template 103 | + SwiftTests - Unit tests with XCTest Framework 104 | 105 | Usage 106 | -------------------- 107 | Individuals are welcome to use the code with commercial and open-source projects. As a courtesy, please provide attribution to waynewbishop.com. For more information, review the complete license agreement. 108 | 109 | 110 | Branches 111 | -------------------- 112 | + master - The production branch. Clone or fork this repository for the latest copy 113 | + develop - The active Swift 4.2 development branch. Swift 4.2 [pull requests](https://help.github.com/articles/creating-a-pull-request) should be directed to this branch 114 | 115 | 116 | 117 | Other Projects 118 | -------------------- 119 | 120 | + EKAlgorithms - A set of computer exercises implemented in Objective-C 121 | + Algorithms - A playground for common questions implemented in Ruby 122 | 123 | 124 | Questions 125 | -------------------- 126 | 127 | Have a question? Feel free to contact me on Twitter or online. 128 | 129 | -------------------------------------------------------------------------------- /Source/Extensions/Array.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Array.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/1/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | extension Array where Element: Comparable { 13 | 14 | 15 | //determines the longest sequence of specified values 16 | func longestSequence(of key: Element) -> Int { 17 | 18 | //initial values 19 | var current: Element 20 | var counter: Int = 0 21 | var longest: Int = 0 22 | 23 | //iterate through list - O(n) 24 | for s in self { 25 | 26 | //current iteration 27 | current = s 28 | 29 | if current == key { 30 | counter += 1 31 | } 32 | else { 33 | counter = 0 34 | } 35 | 36 | //preserve the longest sequence 37 | if counter >= longest { 38 | longest = counter 39 | } 40 | } 41 | 42 | //return count results 43 | return longest 44 | 45 | } 46 | 47 | 48 | //MARK: Index Operation 49 | 50 | 51 | //returns middle index 52 | func midIndex() -> Index { 53 | return startIndex + (count / 2) 54 | } 55 | 56 | 57 | //MARK: - Binary Search 58 | 59 | 60 | /* 61 | binary search algorithm. Find the value at a specified index. 62 | note the use array slicing to adjust the upper and lower array bounds. 63 | returns true if the key was found in the sequence. Average performance‎: ‎O(log n). 64 | */ 65 | 66 | 67 | mutating func binarySearch(forElement key: Element) -> Bool { 68 | 69 | 70 | var result = false 71 | 72 | //establish indices 73 | let min = self.startIndex 74 | let max = self.endIndex - 1 75 | let mid = self.midIndex() 76 | 77 | 78 | //check bounds 79 | if key > self[max] || key < self[min] { 80 | print("search value \(key) not found..") 81 | return false 82 | } 83 | 84 | 85 | //evaluate chosen number.. 86 | let n = self[mid] 87 | 88 | 89 | print(String(describing: n) + "value attempted..") 90 | 91 | 92 | if n > key { 93 | var slice = Array(self[min...mid - 1]) 94 | result = slice.binarySearch(forElement: key) 95 | } 96 | 97 | else if n < key { 98 | var slice = Array(self[mid + 1...max]) 99 | result = slice.binarySearch(forElement: key) 100 | } 101 | 102 | else { 103 | print("search value \(key) found..") 104 | result = true 105 | } 106 | 107 | return result 108 | } 109 | 110 | 111 | 112 | //MARK: - Linear Search 113 | 114 | 115 | /* 116 | linear search algorithm - use fast enumeration to iterate through a sequence 117 | of values. performance of O(n). 118 | */ 119 | 120 | func linearSearch(forElement key: Element) -> Bool { 121 | 122 | //check all possible values 123 | for number in self { 124 | if number == key { 125 | return true 126 | } 127 | } 128 | 129 | return false 130 | 131 | } 132 | 133 | 134 | 135 | //MARK: - Insertion Sort 136 | 137 | 138 | /* 139 | insertion sort algorithm - rank set of random numbers lowest to highest by 140 | inserting numbers based on a sorted and unsorted side. performance of O(n2). 141 | */ 142 | 143 | func insertionSort() -> Array { 144 | 145 | 146 | //check for trivial case 147 | guard self.count > 1 else { 148 | return self 149 | } 150 | 151 | 152 | var output: Array = self 153 | 154 | for primaryindex in 0.. -1 { 161 | 162 | print("comparing \(key) and \(output[secondaryindex])") 163 | 164 | if key < output[secondaryindex] { 165 | 166 | //move into correct position 167 | output.remove(at: secondaryindex + 1) 168 | output.insert(key, at: secondaryindex) 169 | } 170 | 171 | secondaryindex -= 1 172 | } 173 | 174 | } 175 | 176 | return output 177 | 178 | } 179 | 180 | 181 | 182 | 183 | //MARK: - Bubble Sort 184 | 185 | 186 | /* 187 | bubble sort algorithm - rank items from the lowest to highest by swapping 188 | groups of two items from left to right. The highest item in the set will bubble up to the 189 | right side of the set after the first iteration. performance of O(n2). 190 | */ 191 | 192 | 193 | func bubbleSort() -> Array { 194 | 195 | 196 | //check for trivial case 197 | guard self.count > 1 else { 198 | return self 199 | } 200 | 201 | 202 | //mutated copy 203 | var output: Array = self 204 | 205 | 206 | for primaryIndex in 0.. output[secondaryIndex + 1]) { 221 | output.swapAt(secondaryIndex, secondaryIndex + 1) 222 | } 223 | } 224 | } 225 | 226 | 227 | return output 228 | 229 | } 230 | 231 | 232 | 233 | //MARK: - Selection Sort 234 | 235 | /* 236 | selection sort algorithm - rank items from the lowest to highest by iterating through 237 | the array and swapping the current iteration with the lowest value in the rest of the array 238 | until it reaches the end of the array. performance of O(n2). 239 | */ 240 | 241 | func selectionSort() -> Array { 242 | 243 | 244 | //check for trivial case 245 | guard self.count > 1 else { 246 | return self 247 | } 248 | 249 | 250 | //mutated copy 251 | var output: Array = self 252 | 253 | 254 | for primaryindex in 0.. output[secondaryindex] { 267 | minimum = secondaryindex 268 | } 269 | 270 | secondaryindex += 1 271 | } 272 | 273 | 274 | // swap minimum value with array iteration 275 | if primaryindex != minimum { 276 | output.swapAt(primaryindex, minimum) 277 | } 278 | 279 | } 280 | 281 | 282 | return output 283 | 284 | } 285 | 286 | 287 | 288 | //MARK: - Quick Sort 289 | 290 | 291 | /* 292 | quicksort algorithm - Ranks numbers through a series of swaps. 293 | Based on "conceptually" sorting a collection subset based on a "wall" and "pivot". 294 | Best case performance of O(n log(n)). Worst case performance of O(n2). 295 | */ 296 | 297 | mutating func quickSort() -> Array { 298 | 299 | 300 | func qSort(start startIndex: Int, _ pivot: Int) { 301 | 302 | if (startIndex < pivot) { 303 | let iPivot = qPartition(start: startIndex, pivot) 304 | qSort(start: startIndex, iPivot - 1) 305 | qSort(start: iPivot + 1, pivot) 306 | } 307 | } 308 | 309 | 310 | qSort(start: 0, self.endIndex - 1) 311 | return self 312 | 313 | } 314 | 315 | 316 | 317 | //sorts collection-range based on pivot 318 | mutating func qPartition(start startIndex: Int, _ pivot: Int) -> Int { 319 | 320 | var wallIndex: Int = startIndex 321 | 322 | 323 | //compare range with pivot 324 | for currentIndex in wallIndex.. Void) { 23 | for i in 0...self { 24 | closure(i) 25 | } 26 | } 27 | 28 | 29 | 30 | //build fibonacci sequence to a specified position - default 31 | func fibNormal() -> Array? { 32 | 33 | 34 | //check trivial condition 35 | guard self > 2 else { 36 | return nil 37 | } 38 | 39 | 40 | //initialize the sequence 41 | var sequence: Array = [0, 1] 42 | 43 | 44 | var i: Int = sequence.count 45 | 46 | while i != self { 47 | 48 | let results: Int = sequence[i - 1] + sequence[i - 2] 49 | sequence.append(results) 50 | 51 | i += 1 52 | } 53 | 54 | 55 | return sequence 56 | 57 | } 58 | 59 | 60 | //build fibonacci sequence to a specified position - recursive 61 | mutating func fibRecursive(_ sequence: Array = [0, 1]) -> Array? { 62 | 63 | 64 | var final = Array() 65 | 66 | 67 | //mutated copy 68 | var output = sequence 69 | 70 | 71 | //check trivial condition 72 | guard self > 2 else { 73 | return nil 74 | } 75 | 76 | 77 | let i: Int = output.count 78 | 79 | 80 | //set base condition 81 | if i == self { 82 | return output 83 | } 84 | 85 | 86 | let results: Int = output[i - 1] + output[i - 2] 87 | output.append(results) 88 | 89 | 90 | //set iteration 91 | final = self.fibRecursive(output)! 92 | 93 | 94 | return final 95 | 96 | } 97 | 98 | 99 | //build fibonacci sequence to a specified position - trailing closure 100 | func fibClosure(withFormula formula: (Array) -> Int) -> Array! { 101 | 102 | 103 | //check trivial condition 104 | guard self > 2 else { 105 | return nil 106 | } 107 | 108 | 109 | //initialize the sequence 110 | var sequence: Array = [0, 1] 111 | 112 | var i: Int = sequence.count 113 | 114 | while i != self { 115 | 116 | let results: Int = formula(sequence) 117 | sequence.append(results) 118 | 119 | i += 1 120 | } 121 | 122 | 123 | return sequence 124 | 125 | 126 | } //end function 127 | 128 | 129 | /* 130 | example of dynamic programming. Based on memoization, this nested function 131 | produces the fibonacci sequence in linear time O(n). Also, note how the final 132 | answer is obtained in constant time O(1). 133 | */ 134 | 135 | //calculate results 136 | func fibMemoized() -> Int { 137 | 138 | 139 | //builds array sequence 140 | func fibSequence(_ sequence: Array = [0, 1]) -> Array { 141 | 142 | print("fibSequence called..") 143 | 144 | var final = Array() 145 | 146 | 147 | //mutated copy 148 | var output = sequence 149 | 150 | 151 | let i: Int = output.count 152 | 153 | 154 | //set base condition - linear time O(n) 155 | if i == self { 156 | return output 157 | } 158 | 159 | 160 | let results: Int = output[i - 1] + output[i - 2] 161 | output.append(results) 162 | 163 | 164 | //set iteration 165 | final = fibSequence(output) 166 | 167 | return final 168 | 169 | 170 | } //end function 171 | 172 | 173 | 174 | //calculate final product - constant time O(1) 175 | let results = fibSequence() 176 | let answer: Int = results[results.endIndex - 1] + results[results.endIndex - 2] 177 | return answer 178 | 179 | } 180 | 181 | 182 | } 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /Source/Extensions/Keyable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Keyable.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 10/10/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | //note: an extension on a protocol 13 | 14 | extension Keyable { 15 | 16 | 17 | //compute table index 18 | func hashValue(for key: String!, using buckets: Array) -> Int { 19 | 20 | 21 | var remainder: Int = 0 22 | var divisor: Int = 0 23 | 24 | 25 | //trivial case 26 | guard key != nil else { 27 | return -1 28 | } 29 | 30 | 31 | for item in key.unicodeScalars { 32 | divisor += Int(item.value) 33 | } 34 | 35 | 36 | /* 37 | note: modular math is used to calculate a hash value. The bucket count is used 38 | as the dividend to ensure all possible outcomes are between 0 and the collection size. 39 | */ 40 | 41 | remainder = divisor % buckets.count 42 | 43 | return remainder 44 | } 45 | 46 | } 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Source/Extensions/Sortable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sortable.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/1/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | //note: an extension on a protocol 13 | 14 | extension Sortable { 15 | 16 | 17 | func isSorted(_ sequence: Array) -> Bool { 18 | 19 | 20 | //check trivial cases 21 | guard sequence.count >= 1 else { 22 | return true 23 | } 24 | 25 | var index = sequence.startIndex 26 | 27 | 28 | //compare sequence values 29 | while index < sequence.endIndex - 1 { 30 | if sequence[index] > sequence[sequence.index(after: index)] { 31 | return false 32 | } 33 | index = sequence.index(after: index) 34 | } 35 | 36 | return true 37 | 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Source/Extensions/String.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/1/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | 13 | extension String: Keyable { 14 | 15 | //hash table requirement 16 | var keystring: String { 17 | return self 18 | } 19 | 20 | 21 | //compute the length 22 | var length: Int { 23 | return self.count 24 | } 25 | 26 | 27 | 28 | 29 | //determine if all characters are unique 30 | func isStringUnique() -> Bool { 31 | 32 | //evaluate trival case 33 | guard self.count < 128 else { 34 | return false 35 | } 36 | 37 | 38 | //match unicode representation - O(n) 39 | var list = Array(repeatElement(nil, count: 128)) 40 | 41 | for scalar in self.unicodeScalars { 42 | let unicode = Int(scalar.value) 43 | 44 | if list[unicode] != nil { 45 | return false 46 | } 47 | list[unicode] = true 48 | } 49 | 50 | return true 51 | } 52 | 53 | 54 | 55 | //formats a string to date format 56 | var datevalue: Date! { 57 | 58 | let stringFormatter = DateFormatter() 59 | stringFormatter.dateFormat = "MM-dd-yyyy" 60 | stringFormatter.locale = Locale(identifier: "en_US_POSIX") 61 | 62 | //check for correct date format 63 | if let d = stringFormatter.date(from: self) { 64 | return Date(timeInterval: 0, since: d) 65 | } 66 | else { 67 | return nil 68 | } 69 | 70 | } 71 | 72 | 73 | //returns characters up to a specified integer 74 | func substring(to: Int) -> String { 75 | 76 | //define the range 77 | let range = self.index(self.startIndex, offsetBy: to) 78 | 79 | //return self.substring(to: range) - Swift 3.0 80 | 81 | return String(self[.. String { 87 | return self.replacingOccurrences(of: element, with: replacement) 88 | } 89 | 90 | 91 | //removes empty string content 92 | func removingWhitespace() -> String { 93 | return self.replace(element: " ", replacement: "") 94 | } 95 | 96 | 97 | //create a unique identifer based on date 98 | func identifierWithDate(date: Date) -> String { 99 | 100 | let cleartext = self + String(describing: date) 101 | return String(cleartext.hashValue) 102 | } 103 | 104 | 105 | //reverse string order 106 | func reverse() -> String { 107 | 108 | /* 109 | notes: While this operation would normally be done with the 110 | native characters.reversed() method, this has been added as an example interview question. 111 | */ 112 | 113 | //convert to array 114 | var characters = Array(self) 115 | 116 | var findex: Int = characters.startIndex 117 | var bindex: Int = characters.endIndex - 1 118 | 119 | 120 | while findex < bindex { 121 | 122 | //swap(&characters[findex], &characters[bindex]) - Swift 3.0 123 | characters.swapAt(findex, bindex) 124 | 125 | //update values 126 | findex += 1 127 | bindex -= 1 128 | 129 | 130 | } //end while 131 | 132 | 133 | return String(characters) 134 | 135 | } 136 | 137 | 138 | } 139 | -------------------------------------------------------------------------------- /Source/Extensions/XCTestCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XCTestCase.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 10/12/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | @testable import SwiftStructures 13 | 14 | extension XCTestCase { 15 | 16 | //special evaluation test case for hash tables.. 17 | func XCAssertSuccess(_ expression: Result, _ message: String) { 18 | 19 | //TODO: complete functionality for hashtable.contains() function.. 20 | 21 | } 22 | 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /Source/Factories/BSTree.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BSTree.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/16/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /* 12 | note: self-balancing binary search tree (BST). Elements are positioned based on their value. 13 | After insertion, model is checked for balance and automatically completes required rotations. 14 | */ 15 | 16 | 17 | class BSTree{ 18 | 19 | var root = BSNode() 20 | private var elementStack = Stack>() 21 | 22 | 23 | func append(element key: T) { 24 | 25 | 26 | //initialize root 27 | guard root.key != nil else { 28 | 29 | root.key = key 30 | root.height = 0 31 | 32 | return 33 | } 34 | 35 | 36 | //set initial indicator 37 | var current: BSNode = root 38 | 39 | 40 | while current.key != nil { 41 | 42 | //send reference of current item to stack 43 | push(element: ¤t) 44 | 45 | 46 | //check left side 47 | if key < current.key! { 48 | 49 | if current.left != nil { 50 | current = current.left! 51 | } 52 | 53 | 54 | else { 55 | 56 | //create new element 57 | let childToAdd = BSNode() 58 | childToAdd.key = key 59 | childToAdd.height = 0 60 | current.left = childToAdd 61 | break 62 | } 63 | } 64 | 65 | //check right side 66 | if key > current.key! { 67 | 68 | if current.right != nil { 69 | current = current.right! 70 | } 71 | 72 | 73 | else { 74 | 75 | //create new element 76 | let childToAdd = BSNode() 77 | childToAdd.key = key 78 | childToAdd.height = 0 79 | current.right = childToAdd 80 | break 81 | } 82 | } 83 | 84 | } //end while 85 | 86 | 87 | //calculate height and balance of call stack.. 88 | rebalance() 89 | 90 | } 91 | 92 | 93 | //equality test - O(log n) 94 | func contains(_ key: T) -> Bool { 95 | 96 | var current: BSNode? = root 97 | 98 | while current != nil { 99 | 100 | guard let testkey = current?.key else { 101 | return false 102 | } 103 | 104 | //test match 105 | if testkey == key { 106 | return true 107 | } 108 | 109 | //check left side 110 | if key < testkey { 111 | if current?.left != nil { 112 | current = current?.left 113 | continue 114 | } 115 | else { 116 | return false 117 | } 118 | } 119 | 120 | //check right side 121 | if key > testkey { 122 | if current?.right != nil { 123 | current = current?.right 124 | continue 125 | } 126 | else { 127 | return false 128 | } 129 | } 130 | 131 | } //end while 132 | 133 | return false 134 | } 135 | 136 | 137 | 138 | //stack elements for later processing - memoization 139 | private func push(element: inout BSNode) { 140 | elementStack.push(withKey: element) 141 | print("the stack count is: \(elementStack.count)") 142 | } 143 | 144 | 145 | //determine height and balance 146 | private func rebalance() { 147 | 148 | for _ in stride(from: elementStack.count, through: 1, by: -1) { 149 | 150 | //obtain generic stack node - by reference 151 | let current = elementStack.peek() 152 | 153 | guard let bsNode: BSNode = current.key else { 154 | print("element reference not found..") 155 | continue 156 | } 157 | 158 | setHeight(for: bsNode) 159 | rotate(element: bsNode) 160 | 161 | 162 | //remove stacked item 163 | elementStack.pop() 164 | } 165 | } 166 | 167 | 168 | //MARK: Height Methods 169 | 170 | 171 | private func findHeight(of element: BSNode?) -> Int { 172 | 173 | //check empty leaves 174 | guard let bsNode = element else { 175 | return -1 176 | } 177 | 178 | return bsNode.height 179 | } 180 | 181 | 182 | private func setHeight(for element: BSNode) { 183 | 184 | //set leaf variables 185 | var elementHeight: Int = 0 186 | 187 | //do comparison and calculate height 188 | elementHeight = max(findHeight(of: element.left), findHeight(of: element.right)) + 1 189 | element.height = elementHeight 190 | 191 | } 192 | 193 | 194 | //MARK: Balancing Methods 195 | 196 | 197 | 198 | //determine if the tree is "balanced" - operations on a balanced tree is O(log n) 199 | func isTreeBalanced(for element: BSNode?) -> Bool { 200 | 201 | guard element?.key != nil else { 202 | print("no element provided..") 203 | return false 204 | } 205 | 206 | 207 | //use absolute value to manage right and left imbalances 208 | if (abs(findHeight(of: element?.left) - findHeight(of: element?.right)) <= 1) { 209 | return true 210 | } 211 | else { 212 | return false 213 | } 214 | } 215 | 216 | 217 | 218 | //perform left or right rotation 219 | private func rotate(element: BSNode) { 220 | 221 | guard element.key != nil else { 222 | print("cannot rotate: no key provided..") 223 | return 224 | } 225 | 226 | 227 | if (self.isTreeBalanced(for: element) == true) { 228 | print("node: \(element.key!) already balanced..") 229 | return 230 | } 231 | 232 | 233 | //create new element 234 | let childToUse = BSNode() 235 | childToUse.height = 0 236 | childToUse.key = element.key 237 | 238 | 239 | //determine side imbalance 240 | let rightSide = findHeight(of: element.left) - findHeight(of: element.right) 241 | let leftSide = findHeight(of: element.right) - findHeight(of: element.left) 242 | 243 | 244 | if rightSide > 1 { 245 | 246 | print("\n starting right rotation on \(element.key!)..") 247 | 248 | //reset the root node 249 | element.key = element.left?.key 250 | element.height = findHeight(of: element.left) 251 | 252 | 253 | //assign the new right node 254 | element.right = childToUse 255 | 256 | 257 | //adjust the left node 258 | element.left = element.left?.left 259 | element.left?.height = 0 260 | 261 | print("root is: \(element.key!) | left is : \(element.left!.key!) | right is : \(element.right!.key!)..") 262 | } 263 | 264 | else if leftSide > 1 { 265 | 266 | print("\n starting left rotation on \(element.key!)..") 267 | 268 | //reset the root node 269 | element.key = element.right?.key 270 | element.height = findHeight(of: element.right) 271 | 272 | 273 | //assign the new left node 274 | element.left = childToUse 275 | 276 | 277 | //adjust the right node 278 | element.right = element.right?.right 279 | element.right?.height = 0 280 | 281 | print("root is: \(element.key!) | left is : \(element.left!.key!) | right is : \(element.right!.key!)..") 282 | 283 | } 284 | } 285 | 286 | 287 | 288 | } 289 | -------------------------------------------------------------------------------- /Source/Factories/Blockchain.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Blockchain.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 1/31/18. 6 | // Copyright © 2018 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public class Blockchain: Graph { 13 | 14 | var chain = Array() 15 | var queue = Queue() 16 | var threshold: Int 17 | 18 | 19 | init(ithreshold: Int = 3) { 20 | 21 | threshold = ithreshold 22 | super.init(directed: false) 23 | 24 | 25 | chain.append(genesisBlock()) 26 | } 27 | 28 | 29 | 30 | //MARK: helper functions 31 | 32 | 33 | //starting block 34 | private func genesisBlock()-> Block { 35 | 36 | let firstBlock = Block() 37 | 38 | firstBlock.id = blockIdentifier() 39 | firstBlock.description = "Genesis Block" 40 | 41 | return firstBlock 42 | } 43 | 44 | 45 | //broadcast latest block to peers 46 | func broadcast(to peer: inout Peer) { 47 | peer.chain = self.chain 48 | } 49 | 50 | 51 | 52 | //obtain latest block 53 | private func currentBlock()-> Block { 54 | return chain[chain.endIndex - 1] 55 | } 56 | 57 | 58 | //generate block identifier (e.g. potential mining operation..) 59 | private func blockIdentifier() -> String { 60 | return UUID().uuidString 61 | } 62 | 63 | 64 | 65 | 66 | class Miner { 67 | 68 | 69 | //poll the network for pending exchanges.. 70 | func poll(startingv: Vertex, network: Blockchain) { 71 | 72 | 73 | /* 74 | note: this sequence performs a graph traversal via bfs 75 | (breadth-first search). Note the trailing closure declared 76 | as an inout variable. This provides the mechanisim to update effected 77 | peers "by reference". 78 | */ 79 | 80 | 81 | network.traverse(startingv) { ( node: inout Vertex) -> () in 82 | 83 | //trival case 84 | guard let peer = node as? Peer else { 85 | return 86 | } 87 | 88 | 89 | /* 90 | note: exchanges are queued before they are 91 | added into the main blockchain. 92 | */ 93 | 94 | let queue = network.queue 95 | let threshold = network.threshold 96 | let intentions = peer.exchanges(requester: self) 97 | 98 | 99 | for exchange in intentions { 100 | 101 | 102 | //queue exchange 103 | queue.enQueue(exchange) 104 | print("queued exchange of $\(exchange.amount).") 105 | 106 | 107 | if queue.count == threshold { 108 | 109 | /* 110 | note: due to the potential complexity in mining 111 | a new block, this process would be initiated through an 112 | asynchronous process. 113 | */ 114 | 115 | let newBlock = self.createBlock(for: network) 116 | 117 | 118 | //update main network chain 119 | network.chain.append(newBlock) 120 | 121 | } 122 | 123 | } //end for 124 | 125 | 126 | peer.flush(requester: self) 127 | peer.visited = true 128 | 129 | } 130 | 131 | } 132 | 133 | 134 | 135 | private func createBlock(for network: Blockchain) -> Block { 136 | 137 | //establish queue 138 | let queue = network.queue 139 | let newblock = Block() 140 | var transactions = Array() 141 | 142 | 143 | /* 144 | note: dequeue all pending exchanges from the main queue into a single block. note how the 145 | queue is a member of the network a not the specific Miner. As a result, 146 | other miner instances could theroetically access the shared queue to 147 | push exchanges. 148 | */ 149 | 150 | while queue.count != 0 { 151 | if let exchange = queue.deQueue() { 152 | transactions.append(exchange) 153 | } 154 | } 155 | 156 | 157 | //build the new block 158 | newblock.miner = self 159 | newblock.id = network.blockIdentifier() 160 | newblock.previous = network.currentBlock().id 161 | newblock.transactions = transactions 162 | 163 | return newblock 164 | 165 | } 166 | 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /Source/Factories/EnumModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EnumModel.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 4/25/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | //sample implementation model for the recursive enum model "Algorithm" 13 | 14 | class EnumModel{ 15 | 16 | 17 | func evaluate(withModel model: Algorithm) -> Array! { 18 | 19 | 20 | switch model { 21 | 22 | 23 | case .Empty: 24 | return nil 25 | 26 | 27 | case let .Elements(elementList): 28 | return elementList 29 | 30 | 31 | case let .InsertionSort(elementList): 32 | 33 | 34 | //evaluate sequence 35 | let output = evaluate(withModel: elementList) 36 | return output?.insertionSort() 37 | 38 | 39 | case let .BubbleSort(elementList): 40 | 41 | 42 | //evaluate sequence 43 | let output = evaluate(withModel: elementList) 44 | return output?.bubbleSort() 45 | 46 | 47 | case let .SelectionSort(elementList): 48 | 49 | 50 | //evaluate sequence 51 | let output = evaluate(withModel: elementList) 52 | return output?.selectionSort() 53 | 54 | 55 | } //end switch 56 | 57 | 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Source/Factories/Graph.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Graph.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/7/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public class Graph { 13 | 14 | 15 | //declare a default directed graph canvas 16 | var canvas: Array 17 | var isDirected: Bool 18 | 19 | 20 | init(directed: Bool = true) { 21 | canvas = Array() 22 | isDirected = directed 23 | } 24 | 25 | 26 | //add vertex to graph canvas 27 | func addVertex(element: Vertex) { 28 | canvas.append(element) 29 | } 30 | 31 | 32 | 33 | //add edge to source vertex 34 | func addEdge(source: Vertex, neighbor: Vertex, weight: Int) { 35 | 36 | 37 | //create a new edge 38 | let newEdge = Edge() 39 | 40 | 41 | //establish the default properties 42 | newEdge.neighbor = neighbor 43 | newEdge.weight = weight 44 | source.neighbors.append(newEdge) 45 | 46 | 47 | print("The neighbor of vertex: \(source.key as String?) is \(neighbor.key as String?)..") 48 | 49 | 50 | //check condition for an undirected graph 51 | if isDirected == false { 52 | 53 | 54 | //create a new reversed edge 55 | let reverseEdge = Edge() 56 | 57 | 58 | //establish the reversed properties 59 | reverseEdge.neighbor = source 60 | reverseEdge.weight = weight 61 | neighbor.neighbors.append(reverseEdge) 62 | 63 | print("The neighbor of vertex: \(neighbor.key as String?) is \(source.key as String?)..") 64 | 65 | } 66 | 67 | 68 | } 69 | 70 | 71 | 72 | 73 | 74 | /* reverse the sequence of paths given the shortest path. 75 | process analagous to reversing a linked list. */ 76 | 77 | func reversePath(_ head: Path!, source: Vertex) -> Path! { 78 | 79 | 80 | guard head != nil else { 81 | return head 82 | } 83 | 84 | //mutated copy 85 | var output = head 86 | 87 | 88 | var current: Path! = output 89 | var prev: Path! 90 | var next: Path! 91 | 92 | 93 | while(current != nil) { 94 | next = current.previous 95 | current.previous = prev 96 | prev = current 97 | current = next 98 | } 99 | 100 | 101 | //append the source path to the sequence 102 | let sourcePath: Path = Path() 103 | 104 | sourcePath.destination = source 105 | sourcePath.previous = prev 106 | sourcePath.total = 0 107 | 108 | output = sourcePath 109 | 110 | 111 | return output 112 | 113 | } 114 | 115 | 116 | 117 | 118 | //process Dijkstra's shortest path algorthim 119 | func processDijkstra(_ source: Vertex, destination: Vertex) -> Path? { 120 | 121 | 122 | var frontier: Array = Array() 123 | var finalPaths: Array = Array() 124 | 125 | 126 | //use source edges to create the frontier 127 | for e in source.neighbors { 128 | 129 | let newPath: Path = Path() 130 | 131 | 132 | newPath.destination = e.neighbor 133 | newPath.previous = nil 134 | newPath.total = e.weight 135 | 136 | 137 | //add the new path to the frontier 138 | frontier.append(newPath) 139 | 140 | } 141 | 142 | 143 | //construct the best path 144 | var bestPath: Path = Path() 145 | 146 | 147 | while frontier.count != 0 { 148 | 149 | bestPath = Path() 150 | 151 | //support path changes using the greedy approach 152 | var pathIndex: Int = 0 153 | 154 | 155 | for x in 0.. Path? { 219 | 220 | 221 | let frontier: PathHeap = PathHeap() 222 | let finalPaths: PathHeap = PathHeap() 223 | 224 | 225 | //use source edges to create the frontier 226 | for e in source.neighbors { 227 | 228 | let newPath: Path = Path() 229 | 230 | 231 | newPath.destination = e.neighbor 232 | newPath.previous = nil 233 | newPath.total = e.weight 234 | 235 | 236 | //add the new path to the frontier 237 | frontier.enQueue(newPath) 238 | 239 | } 240 | 241 | 242 | //construct the best path 243 | while frontier.count != 0 { 244 | 245 | //use the greedy approach to obtain the best path 246 | guard let bestPath: Path = frontier.peek() else { 247 | break 248 | } 249 | 250 | 251 | //enumerate the bestPath edges 252 | for e in bestPath.destination.neighbors { 253 | 254 | let newPath: Path = Path() 255 | 256 | newPath.destination = e.neighbor 257 | newPath.previous = bestPath 258 | newPath.total = bestPath.total + e.weight 259 | 260 | 261 | //add the new path to the frontier 262 | frontier.enQueue(newPath) 263 | 264 | } 265 | 266 | 267 | //preserve the bestPaths that match destination 268 | if (bestPath.destination.key == destination.key) { 269 | finalPaths.enQueue(bestPath) 270 | } 271 | 272 | 273 | //remove the bestPath from the frontier 274 | frontier.deQueue() 275 | 276 | 277 | } //end while 278 | 279 | 280 | 281 | //obtain the shortest path from the heap 282 | var shortestPath: Path? = Path() 283 | shortestPath = finalPaths.peek() 284 | 285 | 286 | return shortestPath 287 | 288 | } 289 | 290 | 291 | //MARK: traversal algorithms 292 | 293 | 294 | 295 | //bfs traversal with inout closure function 296 | func traverse(_ startingv: Vertex, formula: (_ node: inout Vertex) -> ()) { 297 | 298 | 299 | //establish a new queue 300 | let graphQueue: Queue = Queue() 301 | 302 | 303 | //queue a starting vertex 304 | graphQueue.enQueue(startingv) 305 | 306 | 307 | while !graphQueue.isEmpty() { 308 | 309 | 310 | //traverse the next queued vertex 311 | guard var vitem = graphQueue.deQueue() else { 312 | break 313 | } 314 | 315 | //add unvisited vertices to the queue 316 | for e in vitem.neighbors { 317 | if e.neighbor.visited == false { 318 | print("adding vertex: \(e.neighbor.key) to queue..") 319 | graphQueue.enQueue(e.neighbor) 320 | } 321 | } 322 | 323 | 324 | /* 325 | notes: this demonstrates how to invoke a closure with an inout parameter. 326 | By passing by reference no return value is required. 327 | */ 328 | 329 | //invoke formula 330 | formula(&vitem) 331 | 332 | 333 | } //end while 334 | 335 | 336 | print("graph traversal complete..") 337 | 338 | 339 | } 340 | 341 | 342 | 343 | 344 | //breadth first search 345 | func traverse(_ startingv: Vertex) { 346 | 347 | 348 | //establish a new queue 349 | let graphQueue: Queue = Queue() 350 | 351 | 352 | //queue a starting vertex 353 | graphQueue.enQueue(startingv) 354 | 355 | 356 | while !graphQueue.isEmpty() { 357 | 358 | 359 | //traverse the next queued vertex 360 | guard let vitem = graphQueue.deQueue() else { 361 | break 362 | } 363 | 364 | 365 | //add unvisited vertices to the queue 366 | for e in vitem.neighbors { 367 | if e.neighbor.visited == false { 368 | print("adding vertex: \(e.neighbor.key) to queue..") 369 | graphQueue.enQueue(e.neighbor) 370 | } 371 | } 372 | 373 | 374 | vitem.visited = true 375 | print("traversed vertex: \(vitem.key)..") 376 | 377 | 378 | } //end while 379 | 380 | 381 | print("graph traversal complete..") 382 | 383 | 384 | } //end function 385 | 386 | 387 | 388 | //use bfs with trailing closure to update all values 389 | func update(startingv: Vertex, formula:((Vertex) -> Bool)) { 390 | 391 | 392 | //establish a new queue 393 | let graphQueue: Queue = Queue() 394 | 395 | 396 | //queue a starting vertex 397 | graphQueue.enQueue(startingv) 398 | 399 | 400 | while !graphQueue.isEmpty() { 401 | 402 | //traverse the next queued vertex - Swift 4.0 403 | //let vitem = graphQueue.deQueue() as Vertex! 404 | 405 | //traverse the next queued vertex 406 | guard let vitem = graphQueue.deQueue() else { 407 | break 408 | } 409 | 410 | 411 | //add unvisited vertices to the queue 412 | for e in vitem.neighbors { 413 | if e.neighbor.visited == false { 414 | print("adding vertex: \(e.neighbor.key) to queue..") 415 | graphQueue.enQueue(e.neighbor) 416 | } 417 | } 418 | 419 | 420 | //apply formula.. 421 | if formula(vitem) == false { 422 | print("formula unable to update: \(String(describing: vitem.key))") 423 | } 424 | else { 425 | print("traversed vertex: \(vitem.key)..") 426 | } 427 | 428 | vitem.visited = true 429 | 430 | 431 | } //end while 432 | 433 | 434 | print("graph traversal complete..") 435 | 436 | 437 | } 438 | 439 | 440 | 441 | 442 | 443 | } 444 | -------------------------------------------------------------------------------- /Source/Factories/HashTable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HashTable.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/5/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /* 13 | note: a generic hash table. types supported must conform to the 14 | custom Keyable protocol. 15 | */ 16 | 17 | 18 | class HashTable { 19 | 20 | private var buckets: Array?> 21 | 22 | /* 23 | note: initializing the hash table with an initial capacity shown 24 | for educational purposes only. 25 | */ 26 | init(capacity: Int) { 27 | self.buckets = Array?>(repeatElement(nil, count: capacity)) 28 | } 29 | 30 | 31 | //TODO: create a computed property - hashvalue that calculates the key for a specific index. 32 | 33 | 34 | 35 | //add item to list 36 | func insert(_ element: T) -> Result { 37 | 38 | let result: Result 39 | 40 | 41 | //compute hash 42 | let hashIndex = element.hashValue(for: element.keystring, using: buckets) 43 | 44 | 45 | if hashIndex != -1 { 46 | 47 | let childToUse = Node() 48 | childToUse.key = element 49 | 50 | 51 | //check existing list 52 | if buckets[hashIndex] == nil { 53 | buckets[hashIndex] = childToUse 54 | result = Result.Success 55 | } 56 | 57 | else { 58 | 59 | print("collision occurred. implementing chaining..") 60 | 61 | var head = buckets[hashIndex] as Node? 62 | 63 | //append item 64 | childToUse.next = head 65 | head = childToUse 66 | 67 | 68 | //update chained list 69 | buckets[hashIndex] = head 70 | 71 | result = Result.Collision 72 | } 73 | } 74 | 75 | else { 76 | result = Result.Fail 77 | } 78 | 79 | return result 80 | } 81 | 82 | 83 | 84 | //test for containing element 85 | func contains(_ element: T) -> Bool { 86 | 87 | 88 | //obtain hash index 89 | let hashIndex = element.hashValue(for: element.keystring, using: buckets) 90 | 91 | 92 | guard hashIndex != -1 else { 93 | return false 94 | } 95 | 96 | 97 | if buckets[hashIndex] != nil { 98 | 99 | var current = buckets[hashIndex] 100 | 101 | //check chained list for match 102 | while current != nil { 103 | 104 | /* 105 | note: test for equality. since the user provided input as well as 106 | the hash table contents both conform to the Keyable protocol, table 107 | elements can be interpreted as a Keyable "type". This centralized 108 | conformance allows seemingly different objects to 109 | be compared equally (e.g. String vs Vertex). 110 | */ 111 | 112 | if let item: Keyable = current?.key { 113 | if item.keystring == element.keystring { 114 | return true 115 | } 116 | } 117 | current = current?.next 118 | 119 | } //end while 120 | } 121 | 122 | return false 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /Source/Factories/Heap.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Heap.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/7/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /* 12 | note: a generic heap (e.g. priority queue) algorithm. This class functions 13 | as a min or max heap. 14 | */ 15 | 16 | 17 | class Heap { 18 | 19 | 20 | private var items: Array 21 | private var heapType: HeapType 22 | 23 | 24 | //min-heap default initialization 25 | init(type: HeapType = .Min) { 26 | 27 | items = Array() 28 | heapType = type 29 | } 30 | 31 | 32 | //number of items 33 | var count: Int { 34 | return self.items.count 35 | } 36 | 37 | 38 | //the min or max value 39 | func peek() -> T? { 40 | 41 | if items.count > 0 { 42 | return items[0] //the min or max value 43 | } 44 | else { 45 | return nil 46 | } 47 | } 48 | 49 | 50 | 51 | //addition of new items 52 | func enQueue(_ key: T) { 53 | 54 | items.append(key) 55 | 56 | 57 | var childIndex: Float = Float(items.count) - 1 58 | var parentIndex: Int = 0 59 | 60 | 61 | //calculate parent index 62 | if childIndex != 0 { 63 | parentIndex = Int(floorf((childIndex - 1) / 2)) 64 | } 65 | 66 | 67 | var childToUse: T 68 | var parentToUse: T 69 | 70 | 71 | //use the bottom-up approach 72 | while childIndex != 0 { 73 | 74 | 75 | childToUse = items[Int(childIndex)] 76 | parentToUse = items[parentIndex] 77 | 78 | 79 | //heapify depending on type 80 | switch heapType { 81 | 82 | case .Min: 83 | 84 | //swap child and parent positions 85 | if childToUse <= parentToUse { 86 | items.swapAt(parentIndex, Int(childIndex)) 87 | } 88 | 89 | case .Max: 90 | 91 | //swap child and parent positions 92 | if childToUse >= parentToUse { 93 | items.swapAt(parentIndex, Int(childIndex)) 94 | } 95 | 96 | } 97 | 98 | 99 | //reset indices 100 | childIndex = Float(parentIndex) 101 | 102 | 103 | if childIndex != 0 { 104 | parentIndex = Int(floorf((childIndex - 1) / 2)) 105 | } 106 | 107 | 108 | } //end while 109 | 110 | 111 | } //end function 112 | 113 | } 114 | -------------------------------------------------------------------------------- /Source/Factories/Learning.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Learning.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 10/22/18. 6 | // Copyright © 2018 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | typealias AEClassifierResult = String 12 | 13 | class Learning { 14 | 15 | /* 16 | note: AEClassifier is a model trained with csv data built on MacOS. 17 | to review and experiment with this dataset access the specific MacOS 18 | playground file. 19 | */ 20 | 21 | 22 | func AEPredict(using statement: String) -> AEClassifierResult? { 23 | 24 | let model = AEClassifier() 25 | 26 | guard let prediction = try? model.prediction(text: statement) else { 27 | fatalError("Unexpected runtime error.") 28 | } 29 | 30 | 31 | //return predicted value - String 32 | return prediction.label 33 | 34 | } 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /Source/Factories/LinkedList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkedList.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/7/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | class LinkedList { 13 | 14 | 15 | //new instance 16 | private var head = LLNode() 17 | private var counter: Int = 0 18 | 19 | 20 | 21 | //the number of items - O(1) 22 | var count: Int { 23 | return counter 24 | } 25 | 26 | 27 | //find subscript shortcut 28 | subscript(index: Int) -> LLNode? { 29 | get { 30 | return find(at: index) 31 | } 32 | } 33 | 34 | 35 | //empty list check 36 | func isEmpty() -> Bool { 37 | return counter == 0 || head.key == nil 38 | } 39 | 40 | 41 | 42 | 43 | //add link item 44 | func append(element key: T) { 45 | 46 | 47 | //trivial check 48 | guard head.key != nil else { 49 | head.key = key 50 | counter += 1 51 | return 52 | } 53 | 54 | 55 | var current: LLNode? = head 56 | 57 | 58 | while current != nil { 59 | 60 | if current?.next == nil { 61 | 62 | let childToUse = LLNode() 63 | 64 | childToUse.key = key 65 | childToUse.previous = current 66 | current!.next = childToUse 67 | break 68 | } 69 | 70 | else { 71 | current = current?.next 72 | } 73 | 74 | 75 | } //end while 76 | 77 | counter += 1 78 | } 79 | 80 | 81 | 82 | //print all keys for the class 83 | func printAllKeys() { 84 | 85 | //a dictionary - O(1) 86 | 87 | var current: LLNode? = head 88 | 89 | print("------------------") 90 | 91 | //assign the next instance 92 | 93 | while current != nil { 94 | print("link item is: \(String(describing: current?.key!))") 95 | current = current?.next 96 | } 97 | 98 | } 99 | 100 | 101 | //MARK: Key & index operations 102 | 103 | 104 | //obtain link at a specific index 105 | func find(at index: Int) ->LLNode? { 106 | 107 | 108 | //check empty conditions 109 | if ((index < 0) || (index > (self.count - 1)) || (head.key == nil)) { 110 | return nil 111 | } 112 | 113 | 114 | else { 115 | var current: LLNode = head 116 | var x: Int = 0 117 | 118 | 119 | //cycle through elements 120 | while (index != x) { 121 | current = current.next! 122 | x += 1 123 | } 124 | 125 | return current 126 | 127 | } //end else 128 | } 129 | 130 | 131 | 132 | 133 | //insert at specific index 134 | func insert(_ key: T, at index: Int) { 135 | 136 | 137 | //check for nil conditions 138 | if ((index < 0) || (index > (self.count - 1))) { 139 | print("link index does not exist..") 140 | } 141 | 142 | 143 | //establish the head node 144 | guard head.key != nil else { 145 | head.key = key 146 | counter += 1 147 | return 148 | } 149 | 150 | 151 | //establish the trailer, current and new items 152 | var current: LLNode? = head 153 | var trailer: LLNode? 154 | var listIndex: Int = 0 155 | 156 | 157 | //iterate through the list to find the insertion point 158 | while (current != nil) { 159 | 160 | if (index == listIndex) { 161 | 162 | let childToUse: LLNode = LLNode() 163 | 164 | //create the new node 165 | childToUse.key = key 166 | 167 | 168 | //connect the node infront of the current node 169 | childToUse.next = current 170 | childToUse.previous = trailer 171 | 172 | 173 | //use optional binding when using the trailer 174 | if let linktrailer = trailer { 175 | linktrailer.next = childToUse 176 | childToUse.previous = linktrailer 177 | } 178 | 179 | 180 | //point new node to the current / previous 181 | current!.previous = childToUse 182 | 183 | 184 | //replace the head node if required 185 | if (index == 0) { 186 | head = childToUse 187 | } 188 | 189 | 190 | break 191 | 192 | } //end if 193 | 194 | 195 | //iterate through to the next item 196 | trailer = current 197 | current = current?.next 198 | listIndex += 1 199 | 200 | 201 | } //end while 202 | 203 | counter += 1 204 | 205 | } 206 | 207 | 208 | 209 | 210 | //remove at specific index 211 | func remove(at index: Int) { 212 | 213 | //check for nil conditions 214 | if ((index < 0) || (index > (self.count - 1)) || (head.key == nil)) { 215 | print("link index does not exist..") 216 | return 217 | } 218 | 219 | 220 | var current: LLNode? = head 221 | var trailer: LLNode? 222 | var listIndex: Int = 0 223 | 224 | 225 | //determine if the removal is at the head 226 | if (index == 0) { 227 | current = current?.next 228 | 229 | if let headitem = current { 230 | head = headitem 231 | counter -= 1 232 | } 233 | return 234 | } 235 | 236 | 237 | //iterate through the remaining items 238 | while current != nil { 239 | 240 | if listIndex == index { 241 | 242 | //redirect the trailer and next pointers 243 | trailer!.next = current?.next 244 | current = nil 245 | break 246 | 247 | } 248 | 249 | //update the assignments 250 | trailer = current 251 | current = current?.next 252 | listIndex += 1 253 | 254 | } //end while 255 | 256 | counter -= 1 257 | 258 | } //end function 259 | 260 | 261 | 262 | 263 | 264 | //reverse the order of a linked list 265 | func reverse() { 266 | 267 | //if count == 1 or count == 0,no need to reverse 268 | if self.count <= 1{ 269 | return 270 | } 271 | 272 | 273 | var current : LLNode? = head 274 | var next : LLNode? = nil 275 | 276 | 277 | while(current != nil) { 278 | 279 | //reverse 280 | next = current!.next 281 | current!.next = current!.previous 282 | current!.previous = next 283 | 284 | 285 | if next == nil { 286 | head = current! 287 | } 288 | 289 | //move to next node 290 | current = next 291 | 292 | } 293 | 294 | } 295 | 296 | 297 | 298 | //MARK: Closure operations 299 | 300 | 301 | 302 | /* 303 | notes: These "generic methods" mimic the map & filter array 304 | functions found in the Swift standard library. 305 | */ 306 | 307 | 308 | //filter list content - higher order function 309 | func filter(_ formula: (LLNode) -> Bool) -> LinkedList? { 310 | 311 | 312 | //check for instance 313 | guard head.key != nil else { 314 | return nil 315 | } 316 | 317 | 318 | var current: LLNode! = head 319 | let results: LinkedList? = LinkedList() 320 | 321 | 322 | while current != nil { 323 | 324 | //filter based on formula 325 | if formula(current) == true { 326 | if let key = current.key { 327 | results?.append(element: key) 328 | } 329 | } 330 | 331 | current = current.next 332 | } 333 | 334 | 335 | return results 336 | 337 | } 338 | 339 | 340 | 341 | //map list content - higher order function 342 | func map(_ formula: (LLNode) -> T) -> LinkedList! { 343 | 344 | 345 | //check for instance 346 | guard head.key != nil else { 347 | return nil 348 | } 349 | 350 | 351 | var current: LLNode! = head 352 | let results: LinkedList = LinkedList() 353 | var newKey: T! 354 | 355 | 356 | while current != nil { 357 | 358 | //map based on formula 359 | newKey = formula(current) 360 | 361 | //add non-nil entries 362 | if newKey != nil { 363 | results.append(element: newKey) 364 | } 365 | 366 | 367 | current = current.next 368 | } 369 | 370 | 371 | return results 372 | 373 | } 374 | 375 | 376 | 377 | 378 | } //end class 379 | 380 | 381 | 382 | 383 | 384 | 385 | -------------------------------------------------------------------------------- /Source/Factories/NaiveBayes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NaiveBayes.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/24/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | class NaiveBayes { 13 | 14 | var bayesEvents = Array() 15 | 16 | 17 | //add results to event list 18 | func train(event: Array) { 19 | 20 | 21 | //trivial case 22 | guard event.count != 0 else { 23 | return 24 | } 25 | 26 | 27 | //TODO: //calculate probabilities for all results as they compare to the outcome 28 | 29 | } 30 | 31 | 32 | //estimate outcome based on results 33 | func predict(event: Array) { 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Source/Factories/PathHeap.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PathHeap.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 8/9/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public class PathHeap { 13 | 14 | private var heap: Array 15 | 16 | init() { 17 | heap = Array() 18 | } 19 | 20 | 21 | //the number of frontier items 22 | var count: Int { 23 | return self.heap.count 24 | } 25 | 26 | 27 | 28 | //obtain the minimum path 29 | func peek() -> Path? { 30 | 31 | if heap.count > 0 { 32 | return heap[0] //the shortest path 33 | } 34 | else { 35 | return nil 36 | } 37 | 38 | } 39 | 40 | 41 | 42 | //remove the minimum path 43 | func deQueue() { 44 | 45 | if heap.count > 0 { 46 | heap.remove(at: 0) 47 | } 48 | 49 | } 50 | 51 | 52 | //sort shortest paths into a min-heap (heapify) 53 | func enQueue(_ key: Path) { 54 | 55 | 56 | heap.append(key) 57 | 58 | 59 | var childIndex: Float = Float(heap.count) - 1 60 | var parentIndex: Int = 0 61 | 62 | 63 | //calculate parent index 64 | if childIndex != 0 { 65 | parentIndex = Int(floorf((childIndex - 1) / 2)) 66 | } 67 | 68 | 69 | var childToUse: Path 70 | var parentToUse: Path 71 | 72 | 73 | //use the bottom-up approach 74 | while childIndex != 0 { 75 | 76 | 77 | childToUse = heap[Int(childIndex)] 78 | parentToUse = heap[parentIndex] 79 | 80 | 81 | //swap child and parent positions 82 | if childToUse.total < parentToUse.total { 83 | heap.swapAt(parentIndex, Int(childIndex)) 84 | } 85 | 86 | 87 | //reset indices 88 | childIndex = Float(parentIndex) 89 | 90 | 91 | if childIndex != 0 { 92 | parentIndex = Int(floorf((childIndex - 1) / 2)) 93 | } 94 | 95 | 96 | } //end while 97 | 98 | 99 | } //end function 100 | 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /Source/Factories/Queue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Queue.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/11/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Queue { 12 | 13 | private var top: Node? 14 | private var counter: Int = 0 15 | 16 | init() { 17 | top = Node() 18 | } 19 | 20 | 21 | //the number of items 22 | var count: Int { 23 | return counter 24 | } 25 | 26 | 27 | //MARK: Supporting Functions 28 | 29 | 30 | 31 | //retrieve the top most item 32 | func peek() -> T? { 33 | return top?.key 34 | } 35 | 36 | 37 | 38 | //check for the presence of a value 39 | func isEmpty() -> Bool { 40 | 41 | guard top?.key != nil else { 42 | return true 43 | } 44 | return false 45 | } 46 | 47 | 48 | 49 | //MARK: Queuing Functions 50 | 51 | 52 | //enqueue the specified object 53 | func enQueue(_ key: T) { 54 | 55 | 56 | //trivial case 57 | guard top?.key != nil else { 58 | top?.key = key 59 | counter += 1 60 | return 61 | } 62 | 63 | let childToUse = Node() 64 | var current = top 65 | 66 | 67 | //cycle through the list 68 | while current?.next != nil { 69 | current = current?.next 70 | } 71 | 72 | 73 | //append new item 74 | childToUse.key = key 75 | current?.next = childToUse 76 | counter += 1 77 | } 78 | 79 | 80 | 81 | //retrieve items from the top level - O(1) time 82 | func deQueue() -> T? { 83 | 84 | 85 | //determine key instance 86 | guard top?.key != nil else { 87 | return nil 88 | } 89 | 90 | 91 | //retrieve and queue the next item 92 | let queueItem: T? = top?.key 93 | 94 | 95 | //use optional binding 96 | if let nextItem = top?.next { 97 | top = nextItem 98 | } 99 | else { 100 | top = Node() 101 | } 102 | 103 | counter -= 1 104 | 105 | return queueItem 106 | 107 | } 108 | 109 | 110 | 111 | } //end class 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /Source/Factories/Quicksort.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Quicksort.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 8/13/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /* 12 | notes: file established for testing purposes only. See the quickSort() method within the 13 | Array class extension for current implementation 14 | */ 15 | 16 | 17 | /* 18 | class QuickSort { 19 | 20 | //var sequence: Array = [6, 5, 1, 3, 8, 4, 7, 9, 2] 21 | var sequence: Array = [7, 2, 1, 6, 8, 5, 3, 4] 22 | //var sequence: Array = [1, 2, 3, 4, 5, 6, 7, 8] 23 | //var sequence: Array = [8, 2, 10, 9, 7, 5] 24 | //var sequence: Array = [0, 4, 7, 9, 13, 16, 34] 25 | //var sequence: Array = [2, 5, 3, 8, 9, 5, 6, 7] 26 | //var sequence: Array = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3] 27 | //var sequence: Array = [1, 2, 3, 4, 5] 28 | 29 | 30 | //var sequence: Array = [8, 7, 6, 5, 4, 3, 2, 1] 31 | //var sequence: Array = [6, 5, 4, 3, 2, 1] 32 | //var sequence: Array = [7, 2, 6, 5, 2, 1] 33 | 34 | 35 | 36 | //determines sorting range - performance: O(n log(n)) 37 | func quickSort() -> Array { 38 | 39 | 40 | func qSort(start startIndex: Int, _ pivot: Int) { 41 | 42 | if (startIndex < pivot) { 43 | let iPivot = qPartition(start: startIndex, pivot) 44 | qSort(start: startIndex, iPivot - 1) 45 | qSort(start: iPivot + 1, pivot) 46 | } 47 | 48 | } 49 | 50 | qSort(start: 0, sequence.endIndex - 1) 51 | return sequence 52 | 53 | } 54 | 55 | 56 | 57 | //sorts collection range based on pivot 58 | func qPartition(start startIndex: Int, _ pivot: Int) -> Int { 59 | 60 | var wallIndex: Int = startIndex 61 | 62 | 63 | //compare range with pivot 64 | for currentIndex in wallIndex.. { 13 | 14 | private var top: Node 15 | private var counter: Int = 0 16 | 17 | 18 | init() { 19 | top = Node() 20 | } 21 | 22 | 23 | //the number of items - O(1) 24 | var count: Int { 25 | return counter 26 | } 27 | 28 | 29 | //add item to the stack - O(1) 30 | func push(withKey key: T) { 31 | 32 | 33 | //return trivial case 34 | guard top.key != nil else { 35 | top.key = key 36 | counter += 1 37 | return 38 | } 39 | 40 | 41 | //create new item 42 | let childToUse = Node() 43 | childToUse.key = key 44 | 45 | 46 | //set new created item at top 47 | childToUse.next = top 48 | top = childToUse 49 | 50 | 51 | //set counter 52 | counter += 1 53 | 54 | } 55 | 56 | 57 | 58 | //remove item from the stack - O(1) 59 | func pop() { 60 | 61 | if self.count > 1 { 62 | top = top.next! 63 | 64 | //set counter 65 | counter -= 1 66 | 67 | } 68 | else { 69 | top.key = nil 70 | counter = 0 71 | } 72 | 73 | } 74 | 75 | 76 | //retrieve the top most item - O(1) 77 | func peek() -> Node { 78 | return top 79 | } 80 | 81 | 82 | 83 | //check for value - O(1) 84 | func isEmpty() -> Bool { 85 | 86 | if self.count == 0 { 87 | return true 88 | } 89 | 90 | else { 91 | return false 92 | } 93 | 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Source/Factories/Trie.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Trie.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 10/14/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public class Trie { 13 | 14 | private var root = TrieNode() 15 | 16 | 17 | //find subscript shortcut 18 | subscript(word: String) -> Array? { 19 | get { 20 | return find(word) 21 | } 22 | } 23 | 24 | 25 | 26 | 27 | //builds a tree hierarchy of dictionary content 28 | func append(word keyword: String) { 29 | 30 | 31 | //trivial case 32 | guard keyword.length > 0 else { 33 | return 34 | } 35 | 36 | 37 | var current: TrieNode = root 38 | 39 | 40 | while keyword.length != current.level { 41 | 42 | var childToUse: TrieNode! 43 | let searchKey = keyword.substring(to: current.level + 1) 44 | 45 | 46 | //print("current has \(current.children.count) children..") 47 | 48 | 49 | //iterate through child nodes 50 | for child in current.children { 51 | 52 | if (child.key == searchKey) { 53 | childToUse = child 54 | break 55 | } 56 | } 57 | 58 | 59 | //new node 60 | if childToUse == nil { 61 | 62 | childToUse = TrieNode() 63 | childToUse.key = searchKey 64 | childToUse.level = current.level + 1 65 | current.children.append(childToUse) 66 | } 67 | 68 | 69 | current = childToUse 70 | 71 | 72 | } //end while 73 | 74 | 75 | //final end of word check 76 | if (keyword.length == current.level) { 77 | current.isFinal = true 78 | print("end of word reached!") 79 | return 80 | } 81 | 82 | } //end function 83 | 84 | 85 | 86 | 87 | //find words based on the prefix 88 | func find(_ keyword: String) -> Array? { 89 | 90 | 91 | //trivial case 92 | guard keyword.length > 0 else { 93 | return nil 94 | } 95 | 96 | 97 | var current: TrieNode = root 98 | var wordList = Array() 99 | 100 | 101 | while keyword.length != current.level { 102 | 103 | var childToUse: TrieNode! 104 | let searchKey = keyword.substring(to: current.level + 1) 105 | 106 | 107 | //print("looking for prefix: \(searchKey)..") 108 | 109 | 110 | //iterate through any child nodes 111 | for child in current.children { 112 | 113 | if (child.key == searchKey) { 114 | childToUse = child 115 | current = childToUse 116 | break 117 | } 118 | 119 | } 120 | 121 | 122 | if childToUse == nil { 123 | return nil 124 | } 125 | 126 | 127 | } //end while 128 | 129 | 130 | 131 | //retrieve the keyword and any descendants 132 | if ((current.key == keyword) && (current.isFinal)) { 133 | if let key = current.key { 134 | wordList.append(key) 135 | } 136 | } 137 | 138 | 139 | //include only children that are words 140 | for child in current.children { 141 | 142 | if (child.isFinal == true) { 143 | if let key = child.key { 144 | wordList.append(key) 145 | } 146 | } 147 | } 148 | 149 | 150 | return wordList 151 | 152 | 153 | } //end function 154 | 155 | 156 | } 157 | -------------------------------------------------------------------------------- /Source/Factories/delegation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Delegation.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 5/16/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /* 13 | note: This class describes the Delegation design pattern. 14 | */ 15 | 16 | 17 | class Delegation: IEngineDelegate { 18 | 19 | let iEngine = IEngine() 20 | 21 | 22 | init() { 23 | iEngine.delegate = self 24 | } 25 | 26 | 27 | //start main process 28 | func processContent(withElement element: Int) { 29 | iEngine.processContent(element) 30 | } 31 | 32 | 33 | //MARK: - Delegate Methods 34 | 35 | 36 | //invoked prior to process start 37 | func willProcessContent(message: String) { 38 | print(message) 39 | } 40 | 41 | 42 | //invoked after process completion 43 | func didProcessContent(results: Int) { 44 | print("the result is: \(results)") 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Source/Models/AEClassifier.mlmodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waynewbishop/bishop-algorithms-swift/7d49b71138d6919870a1c0d23e7152e12a9e2e81/Source/Models/AEClassifier.mlmodel -------------------------------------------------------------------------------- /Source/Patterns/Dispatch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dispatch.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/26/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | 10 | import UIKit 11 | import Foundation 12 | 13 | class Dispatch { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Source/Patterns/Model.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Model.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/26/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | 10 | import UIKit 11 | import Foundation 12 | 13 | 14 | class Model: ModelDelegate { 15 | 16 | 17 | let engine: ModelEngine = ModelEngine() 18 | 19 | init() { 20 | engine.delegate = self 21 | } 22 | 23 | 24 | //invoke delegation pattern 25 | func processContent(withElement element: Int) { 26 | engine.processContent(element) 27 | } 28 | 29 | 30 | //MARK: - Delegate Methods 31 | 32 | //invoked prior to process start 33 | func willProcessContent(message: String) { 34 | print(message) 35 | } 36 | 37 | 38 | //invoked after process completion 39 | func didProcessContent(results: Int) { 40 | print("the result is: \(results)") 41 | } 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /Source/Patterns/ModelDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Protocol.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/26/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | //set conforming rules 13 | protocol ModelDelegate { 14 | 15 | func willProcessContent(message: String) 16 | func didProcessContent(results: Int) 17 | } 18 | -------------------------------------------------------------------------------- /Source/Patterns/ModelEngine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Delegate.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/26/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | class ModelEngine { 13 | 14 | 15 | //create protocol instance 16 | var delegate: ModelDelegate? 17 | 18 | 19 | //replicate long running process 20 | func processContent(_ element: Int) { 21 | 22 | 23 | //send initiation message 24 | delegate?.willProcessContent(message: "engine processing successfully initiated..") 25 | 26 | 27 | //perform some basic test operation 28 | let output = element * 2 29 | 30 | 31 | /* 32 | note: In a real application, this content processing could be executed 33 | on a background thread through GCD or some other multithreaded execution. 34 | */ 35 | sleep(2) 36 | 37 | 38 | 39 | //send message (on main thread) 40 | delegate?.didProcessContent(results: output) 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Source/Structures/Archive/BSRecursive.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BSTree.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/26/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /* 13 | note: self-balancing binary search tree (BST). Elements are positioned based on their value. 14 | After insertion, BST model is checked for balance and completes any required rotations. 15 | */ 16 | 17 | 18 | public class BSRecursive { 19 | 20 | 21 | var key: T? 22 | var left: BSRecursive? 23 | var right: BSRecursive? 24 | var height: Int 25 | 26 | 27 | init() { 28 | self.height = -1 29 | } 30 | 31 | 32 | var count: Int { 33 | let left = self.left?.count ?? 0 34 | let right = self.right?.count ?? 0 35 | return left + 1 + right 36 | } 37 | 38 | 39 | 40 | //add item 41 | func append(element key: T) { 42 | 43 | 44 | //check root 45 | guard self.key != nil else { 46 | 47 | self.key = key 48 | self.height = 0 49 | return 50 | } 51 | 52 | 53 | //check left side 54 | if key < self.key! { 55 | 56 | 57 | if self.left != nil { 58 | left?.append(element: key) 59 | } 60 | 61 | 62 | else { 63 | 64 | //new element 65 | let leftElement = BSRecursive() 66 | leftElement.key = key 67 | leftElement.height = 0 68 | 69 | self.left = leftElement 70 | } 71 | 72 | _ = self.setHeight() 73 | 74 | print("traversing left side. element \(self.key!) with height: \(self.height)...") 75 | 76 | _ = self.rotate() 77 | 78 | } 79 | 80 | 81 | //check right side 82 | if key > self.key! { 83 | 84 | 85 | if self.right != nil { 86 | right?.append(element: key) 87 | } 88 | 89 | 90 | else { 91 | 92 | //new element 93 | let rightElement = BSRecursive() 94 | rightElement.key = key 95 | rightElement.height = 0 96 | 97 | self.right = rightElement 98 | } 99 | 100 | _ = self.setHeight() 101 | 102 | print("traversing right side. element \(self.key!) with height: \(self.height)...") 103 | 104 | _ = self.rotate() 105 | 106 | } 107 | 108 | } 109 | 110 | 111 | 112 | 113 | // MARK: - tree balancing algorithms 114 | 115 | 116 | //find element height 117 | func findHeight(of element: BSRecursive!) -> Int { 118 | 119 | guard element != nil else { 120 | return -1 121 | } 122 | 123 | return element.height 124 | 125 | } 126 | 127 | 128 | 129 | //calculate height 130 | func setHeight() -> Bool { 131 | 132 | 133 | //trivial case 134 | guard self.key != nil else { 135 | print("no key provided..") 136 | return false 137 | } 138 | 139 | 140 | //set leaf variables 141 | var elementHeight: Int = 0 142 | 143 | 144 | //do comparison and calculate height 145 | elementHeight = max(findHeight(of: self.left), findHeight(of: self.right)) + 1 146 | 147 | self.height = elementHeight 148 | 149 | return true 150 | } 151 | 152 | 153 | 154 | //determine if the tree is "balanced" - operations on a balanced tree is O(log n) 155 | func isTreeBalanced() -> Bool { 156 | 157 | 158 | guard self.key != nil else { 159 | print("no element provided..") 160 | return false 161 | } 162 | 163 | 164 | //use absolute value to manage right and left imbalances 165 | if (abs(findHeight(of: self.left) - findHeight(of: self.right)) <= 1) { 166 | return true 167 | } 168 | else { 169 | return false 170 | } 171 | 172 | 173 | } 174 | 175 | 176 | 177 | 178 | //rotate model - if required 179 | func rotate() -> Bool! { 180 | 181 | 182 | guard self.key != nil else { 183 | print("no element provided..") 184 | return false 185 | } 186 | 187 | 188 | if (self.isTreeBalanced() == true) { 189 | print("node \(self.key!) already balanced..") 190 | return true 191 | } 192 | 193 | 194 | //determine rotation type 195 | else { 196 | 197 | 198 | //new leaf node 199 | let childToUse : BSRecursive = BSRecursive() 200 | childToUse.height = 0 201 | childToUse.key = self.key 202 | 203 | 204 | if (findHeight(of: self.left) - findHeight(of: self.right) > 1) { 205 | 206 | print("\n starting right rotation on \(self.key!)..") 207 | 208 | 209 | //reset the root node 210 | self.key = self.left?.key 211 | self.height = findHeight(of: self.left) 212 | 213 | 214 | //assign the new right node 215 | self.right = childToUse 216 | 217 | 218 | //adjust the left node 219 | self.left = self.left?.left 220 | self.left?.height = 0 221 | 222 | print("root is: \(self.key!) | left is : \(self.left!.key!) | right is : \(self.right!.key!)..") 223 | 224 | return true 225 | 226 | } 227 | 228 | 229 | if (findHeight(of: self.right) - findHeight(of: self.left) > 1) { 230 | 231 | print("\n starting left rotation on \(self.key!)..") 232 | 233 | //reset the root node 234 | self.key = self.right?.key 235 | self.height = findHeight(of: self.right) 236 | 237 | 238 | //assign the new left node 239 | self.left = childToUse 240 | 241 | 242 | //adjust the right node 243 | self.right = self.right?.right 244 | self.right?.height = 0 245 | 246 | print("root is: \(self.key!) | left is : \(self.left!.key!) | right is : \(self.right!.key!)..") 247 | 248 | return true 249 | 250 | } 251 | 252 | 253 | return nil 254 | 255 | 256 | 257 | } //end if 258 | 259 | 260 | 261 | } //end function 262 | 263 | 264 | 265 | // MARK: traversal algorithms 266 | 267 | 268 | //use dfs with trailing closure to update all values 269 | func traverse(withFormula formula: (BSRecursive) -> T) { 270 | 271 | 272 | //check for trivial condition 273 | guard self.key != nil else { 274 | print("no key provided..") 275 | return 276 | } 277 | 278 | 279 | //process the left side 280 | if self.left != nil { 281 | left?.traverse(withFormula: formula) 282 | } 283 | 284 | 285 | //invoke formula - apply results 286 | let newKey: T = formula(self) 287 | self.key! = newKey 288 | 289 | 290 | print("...the updated value is: \(self.key!) - height: \(self.height)..") 291 | 292 | 293 | //process the right side 294 | if self.right != nil { 295 | right?.traverse(withFormula: formula) 296 | } 297 | 298 | 299 | } 300 | 301 | 302 | 303 | //regular dfs traversal 304 | func traverse() { 305 | 306 | 307 | //check for trivial condition 308 | guard self.key != nil else { 309 | print("no key provided..") 310 | return 311 | } 312 | 313 | //process the left side 314 | if self.left != nil { 315 | print("\(String(describing: self.left?.key)) added to call stack..") 316 | left?.traverse() 317 | } 318 | 319 | print("...the value is: \(self.key!) - height: \(self.height)..") 320 | 321 | 322 | //process the right side 323 | if self.right != nil { 324 | print("\(String(describing: self.right?.key)) added to call stack..") 325 | right?.traverse() 326 | } 327 | 328 | 329 | } 330 | 331 | 332 | 333 | 334 | } //end class 335 | -------------------------------------------------------------------------------- /Source/Structures/BSNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BSNode.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/16/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | //generic node to be used with binary search trees (BST's) 13 | 14 | class BSNode{ 15 | 16 | var key: T? 17 | var left: BSNode? 18 | var right: BSNode? 19 | var height: Int 20 | 21 | init() { 22 | self.height = -1 23 | } 24 | 25 | 26 | var count: Int { 27 | let left = self.left?.count ?? 0 28 | let right = self.right?.count ?? 0 29 | return left + 1 + right 30 | } 31 | 32 | 33 | //MARK: Traversal Algorithms 34 | 35 | 36 | //execute breadth-first search 37 | func BFSTraverse() -> () { 38 | 39 | //establish a queue 40 | let bsQueue = Queue>() 41 | 42 | //queue a starting node 43 | bsQueue.enQueue(self) 44 | 45 | while !bsQueue.isEmpty() { 46 | 47 | //traverse the next queued node 48 | guard let bitem = bsQueue.deQueue() else { 49 | break 50 | } 51 | 52 | print("now traversing item: \(bitem.key!)") 53 | 54 | //add decendants to the queue 55 | if let left = bitem.left { 56 | bsQueue.enQueue(left) 57 | } 58 | 59 | if let right = bitem.right { 60 | bsQueue.enQueue(right) 61 | } 62 | 63 | 64 | } //end while 65 | 66 | print("bfs traversal complete..") 67 | 68 | } 69 | 70 | 71 | //regular dfs traversal 72 | func DFSTraverse() { 73 | 74 | //trivial condition 75 | guard let key = self.key else { 76 | print("no key provided..") 77 | return 78 | } 79 | 80 | //process the left side 81 | if self.left != nil { 82 | left?.DFSTraverse() 83 | } 84 | 85 | print("...the value is: \(key) - height: \(self.height)..") 86 | 87 | //process the right side 88 | if self.right != nil { 89 | right?.DFSTraverse() 90 | } 91 | } 92 | 93 | 94 | //use dfs with trailing closure to update all values 95 | func DFSTraverse(withFormula formula: (BSNode) -> T) { 96 | 97 | 98 | //check for trivial condition 99 | guard self.key != nil else { 100 | print("no key provided..") 101 | return 102 | } 103 | 104 | 105 | //process the left side 106 | if self.left != nil { 107 | left?.DFSTraverse(withFormula: formula) 108 | } 109 | 110 | 111 | //invoke formula - apply results 112 | let newKey: T = formula(self) 113 | self.key! = newKey 114 | 115 | 116 | print("...the updated value is: \(self.key!) - height: \(self.height)..") 117 | 118 | 119 | //process the right side 120 | if self.right != nil { 121 | right?.DFSTraverse(withFormula: formula) 122 | } 123 | 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /Source/Structures/BayesResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BayesResult.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/24/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /* 13 | notes: following a naive bayes model, the test results of specific features are tracked. 14 | multiple outcomes are grouped as labels 15 | */ 16 | 17 | struct BayesResult { 18 | 19 | 20 | var feature: String 21 | var isOutcome: Bool = false 22 | var labels: Array 23 | var p: Float = 0.0 24 | 25 | 26 | init(feature: String, isOutcome: Bool) { 27 | 28 | self.feature = feature 29 | self.labels = Array() 30 | self.isOutcome = isOutcome 31 | } 32 | 33 | 34 | //add a result 35 | mutating func addLabel(label: Bool) { 36 | labels.append(label) 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Source/Structures/Block.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Block.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 1/31/18. 6 | // Copyright © 2018 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | typealias Hash = String 13 | 14 | public class Block { 15 | 16 | /* 17 | note: all optional values are initiated by the network (e.g. Graph) 18 | and fulfilled by a Miner at runtime. 19 | */ 20 | 21 | var id: String? 22 | var previous: String? 23 | var transactions: Array? 24 | 25 | //track the entity that mined the block.. 26 | var miner: Blockchain.Miner? 27 | var lastModified: Date 28 | var description: String? 29 | 30 | 31 | //initialize class 32 | init() { 33 | self.lastModified = Date() 34 | } 35 | 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /Source/Structures/Edge.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Edge.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/7/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public class Edge { 13 | 14 | var neighbor: Vertex 15 | var weight: Int 16 | 17 | init() { 18 | weight = 0 19 | self.neighbor = Vertex() 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Source/Structures/Exchange.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Exchange.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 2/2/18. 6 | // Copyright © 2018 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | class Exchange { 13 | 14 | var to: Hash 15 | var from: Hash 16 | var amount: Double 17 | var lastModified: Date 18 | 19 | //class initialization 20 | init(_ from: Hash, _ to: Hash, _ amount: Double) { 21 | 22 | self.from = from 23 | self.to = to 24 | self.amount = amount 25 | self.lastModified = Date() 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Source/Structures/IEngine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IEngine.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 5/16/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | //set conforming rules 13 | protocol IEngineDelegate { 14 | 15 | func willProcessContent(message: String) 16 | func didProcessContent(results: Int) 17 | } 18 | 19 | 20 | 21 | class IEngine { 22 | 23 | //create protocol instance 24 | var delegate: IEngineDelegate? 25 | 26 | 27 | 28 | //replicate long running process 29 | func processContent(_ element: Int) { 30 | 31 | 32 | //send initiation message 33 | delegate?.willProcessContent(message: "engine processing successfully initiated..") 34 | 35 | 36 | //perform some basic test operation 37 | let output = element * 2 38 | 39 | 40 | /* 41 | note: In a real application, this content processing could be executed 42 | on a background thread through GCD or some other multithreaded execution. 43 | */ 44 | sleep(2) 45 | 46 | 47 | 48 | //send message (on main thread) 49 | delegate?.didProcessContent(results: output) 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Source/Structures/LLNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LList.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/7/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class LLNode { 12 | 13 | var key: T? 14 | var next: LLNode? 15 | var previous: LLNode? 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Source/Structures/Node.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/2/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | //generic node used for stacks, queues and hash tables 13 | 14 | class Node { 15 | 16 | var key: T? 17 | var next: Node? 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Source/Structures/Path.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 8/4/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | //the path class maintains objects that comprise the "frontier" 12 | 13 | class Path { 14 | 15 | var total: Int 16 | var destination: Vertex 17 | var previous: Path? 18 | 19 | 20 | //object initialization 21 | init(){ 22 | destination = Vertex() 23 | total = 0 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Source/Structures/Peer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Peer.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 1/31/18. 6 | // Copyright © 2018 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /* 13 | note: peers are graph vertices with their own unique characteristics. 14 | this includes the ability to own a copy of the network blockchain and publish their own public key. 15 | when peers want to complete transactions, they publish their "intention" for others (e.g. Miners). 16 | to review. 17 | */ 18 | 19 | public class Peer: Vertex { 20 | 21 | var chain: Array 22 | private var intentions: Array 23 | 24 | 25 | override init(with name: String) { 26 | 27 | chain = Array() 28 | intentions = Array() 29 | 30 | super.init() 31 | super.key = name.identifierWithDate(date: lastModified) 32 | } 33 | 34 | 35 | //create pending exchange 36 | func intent(with to: Peer, for amount: Double) { 37 | 38 | let newExchange = Exchange(self.key, 39 | to.key, amount) 40 | 41 | intentions.append(newExchange) 42 | } 43 | 44 | 45 | //MARK: Miner Actions - only accessible 46 | 47 | 48 | func exchanges(requester miner: Blockchain.Miner) -> Array { 49 | return self.intentions 50 | } 51 | 52 | 53 | func flush(requester miner: Blockchain.Miner) -> () { 54 | self.intentions.removeAll() 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /Source/Structures/Protocols.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Protocols.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/1/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | //determine sort order 13 | protocol Sortable { 14 | 15 | func isSorted(_ sequence: Array) -> Bool 16 | } 17 | 18 | 19 | //determine hash table compliance - (used a type and constraint) 20 | protocol Keyable { 21 | 22 | //conforming types require property 23 | var keystring: String {get} 24 | 25 | 26 | func hashValue(for key: String!, using buckets: Array) -> Int 27 | } 28 | 29 | -------------------------------------------------------------------------------- /Source/Structures/TrieNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Trie.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 8/18/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public class TrieNode { 13 | 14 | var key: String? 15 | var children: Array 16 | var isFinal: Bool 17 | var level: Int 18 | 19 | 20 | init() { 21 | self.children = Array() 22 | self.isFinal = false 23 | self.level = 0 24 | } 25 | 26 | 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /Source/Structures/Vertex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Vertex.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/7/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public class Vertex: Keyable { 13 | 14 | var key = String() 15 | var neighbors = Array() 16 | var visited: Bool = false 17 | var lastModified = Date() 18 | 19 | init() { 20 | } 21 | 22 | init(with name: String) { 23 | self.key = name 24 | } 25 | 26 | //hash table requirement 27 | var keystring: String { 28 | return self.key 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Source/Structures/enums.swift: -------------------------------------------------------------------------------- 1 | // 2 | // enums.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/7/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | //recusive enum used to help build example Algorithm "models" 13 | indirect enum Algorithm { 14 | 15 | case Empty 16 | case Elements(Array) 17 | case InsertionSort(Algorithm) 18 | case BubbleSort(Algorithm) 19 | case SelectionSort(Algorithm) 20 | 21 | } 22 | 23 | 24 | //use for decision tree modeling 25 | enum LearningType { 26 | 27 | case Feature 28 | case Label 29 | } 30 | 31 | //used for generic heap data structure processing 32 | enum HeapType { 33 | 34 | case Min 35 | case Max 36 | } 37 | 38 | 39 | //used for unit test cases 40 | enum SortOrder { 41 | 42 | case Ascending 43 | case Descending 44 | } 45 | 46 | 47 | //used for generic processing 48 | enum Result { 49 | 50 | case Success 51 | case Collision 52 | case NotFound 53 | case NotSupported 54 | case Fail 55 | } 56 | 57 | -------------------------------------------------------------------------------- /SwiftStructures.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftStructures.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftStructures.xcodeproj/project.xcworkspace/xcshareddata/SwiftStructures.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 0579E10E-04DB-4325-9F29-56AB488BD5DA 9 | IDESourceControlProjectName 10 | SwiftStructures 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 1763E0FFAC306B95AEBD1D63B51C7CC88B14B113 14 | https://github.com/waynewbishop/SwiftStructures.git 15 | 16 | IDESourceControlProjectPath 17 | SwiftStructures.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 1763E0FFAC306B95AEBD1D63B51C7CC88B14B113 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/waynewbishop/SwiftStructures.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 1763E0FFAC306B95AEBD1D63B51C7CC88B14B113 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 1763E0FFAC306B95AEBD1D63B51C7CC88B14B113 36 | IDESourceControlWCCName 37 | SwiftStructures 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /SwiftStructures.xcodeproj/project.xcworkspace/xcuserdata/waynebishop.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waynewbishop/bishop-algorithms-swift/7d49b71138d6919870a1c0d23e7152e12a9e2e81/SwiftStructures.xcodeproj/project.xcworkspace/xcuserdata/waynebishop.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SwiftStructures.xcodeproj/xcuserdata/waynebishop.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 40 | 52 | 53 | 54 | 56 | 68 | 69 | 70 | 72 | 84 | 85 | 86 | 88 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /SwiftStructures.xcodeproj/xcuserdata/waynebishop.xcuserdatad/xcschemes/SwiftStructures.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 57 | 63 | 64 | 65 | 66 | 67 | 72 | 73 | 75 | 81 | 82 | 83 | 85 | 91 | 92 | 93 | 95 | 101 | 102 | 103 | 104 | 105 | 111 | 112 | 113 | 114 | 115 | 116 | 126 | 128 | 134 | 135 | 136 | 137 | 138 | 139 | 145 | 147 | 153 | 154 | 155 | 156 | 158 | 159 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /SwiftStructures.xcodeproj/xcuserdata/waynebishop.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftStructures.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | DA34571F19CA3CD700DC871F 16 | 17 | primary 18 | 19 | 20 | DAE001D819C564720035F1A0 21 | 22 | primary 23 | 24 | 25 | DAE001ED19C564720035F1A0 26 | 27 | primary 28 | 29 | 30 | DAE0020119C564C90035F1A0 31 | 32 | primary 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /SwiftTests/BSTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AVLTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/23/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | import XCTest 9 | 10 | 11 | @testable import SwiftStructures 12 | 13 | 14 | 15 | class BSTest: XCTestCase { 16 | 17 | 18 | //called before each test invocation 19 | override func setUp() { 20 | super.setUp() 21 | } 22 | 23 | 24 | 25 | func testCount() { 26 | 27 | let numberList = [1, 2, 3, 5, 234, -20] 28 | let bsTree = BSTree() 29 | 30 | for number in numberList { 31 | bsTree.append(element: number) 32 | } 33 | 34 | bsTree.root.DFSTraverse() 35 | 36 | XCTAssert(bsTree.root.count == numberList.count, "Expected tree's size to be \(numberList.count), got \(bsTree.root.count) instead.") 37 | } 38 | 39 | 40 | 41 | 42 | //essay documentation - single right rotation - O(n) 43 | func testEssayExample() { 44 | 45 | let numberList : Array = [29, 26, 23] 46 | 47 | //build and balance model 48 | let _: Void = buildBSTree(numberList) 49 | 50 | } 51 | 52 | 53 | //input for a balanced avl tree - O(log n) 54 | func testBalancedTree() { 55 | 56 | let numberList : Array = [8, 5, 10, 3, 12, 9, 6, 16] 57 | 58 | //build and balance model 59 | let _: Void = buildBSTree(numberList) 60 | 61 | } 62 | 63 | 64 | //input for multiple right rotations - O(n) 65 | func testRotationRight() { 66 | 67 | let numberList: Array = [29, 26, 23, 20, 19] 68 | 69 | //build and balance model 70 | let _: Void = buildBSTree(numberList) 71 | 72 | } 73 | 74 | 75 | 76 | //input for multiple left rotations - O(n) 77 | func testRotationLeft() { 78 | 79 | let numberList: Array = [19, 20, 23, 26, 29] 80 | 81 | //build and balance model 82 | let _: Void = buildBSTree(numberList) 83 | 84 | } 85 | 86 | 87 | 88 | //input for left and right rotations - 0(n) 89 | func testRotationLeftAndRight() { 90 | 91 | let numberList: Array = [19, 20, 21, 26, 16, 12] 92 | 93 | //build and balance model 94 | let _: Void = buildBSTree(numberList) 95 | } 96 | 97 | 98 | 99 | //MARK: Search Tests 100 | 101 | 102 | 103 | func testContainsRoot() { 104 | 105 | let sequence: Array = [8, 2, 1, 3] 106 | let testvalue: Int = sequence[1] 107 | 108 | //build and balance model 109 | let bsTest: BSTree = buildBSTree(sequence) 110 | 111 | if bsTest.contains(testvalue) == false { 112 | XCTFail("contains bst test fails for value: \(testvalue)..") 113 | } 114 | } 115 | 116 | 117 | func testContainsLeft() { 118 | 119 | let sequence: Array = [8, 2, 1, 3] 120 | let testvalue: Int = sequence[2] 121 | 122 | //build and balance model 123 | let bsTest: BSTree = buildBSTree(sequence) 124 | 125 | if bsTest.contains(testvalue) == false { 126 | XCTFail("contains bst test fails for value: \(testvalue)..") 127 | } 128 | } 129 | 130 | 131 | func testContainsRight() { 132 | 133 | let sequence: Array = [8, 2, 1, 3] 134 | let testvalue: Int = sequence[3] 135 | 136 | //build and balance model 137 | let bsTest: BSTree = buildBSTree(sequence) 138 | 139 | if bsTest.contains(testvalue) == false { 140 | XCTFail("contains bst test fails for value: \(testvalue)..") 141 | } 142 | } 143 | 144 | 145 | func testContainsNoValue() { 146 | 147 | let sequence: Array = [8, 2, 1, 3] 148 | 149 | /* note - value not contained in set..*/ 150 | let testvalue: Int = 32 151 | 152 | 153 | //build and balance model 154 | let bsTest: BSTree = buildBSTree(sequence) 155 | 156 | if bsTest.contains(testvalue) == true { 157 | XCTFail("contains bst test fails for value: \(testvalue)..") 158 | } 159 | } 160 | 161 | 162 | func testBFSTraversal() { 163 | 164 | let sequence: Array = [8, 5, 10, 3, 12, 9, 6, 16] 165 | 166 | //build and balance model 167 | let bsTest: BSTree = buildBSTree(sequence) 168 | 169 | if bsTest.root.count != sequence.count { 170 | XCTFail("incorrect values present for BST model..") 171 | } 172 | 173 | //traverse model 174 | bsTest.root.BFSTraverse() 175 | 176 | } 177 | 178 | 179 | 180 | //MARK: Closure Tests 181 | 182 | 183 | 184 | //update tree values with function 185 | func testTraverseFunction() { 186 | 187 | let bsTest = self.buildClosureTree() 188 | 189 | //invoke formula function 190 | bsTest.root.DFSTraverse(withFormula: traverseFormula) 191 | 192 | } 193 | 194 | 195 | //update bst values with closure expression 196 | func testTraverseExpression() { 197 | 198 | let bsTree = self.buildClosureTree() 199 | var didFail: Bool = false 200 | 201 | 202 | /* 203 | notes: for this test, the didFail variable is known to be 'captured' by the closure expression. 204 | this technique allows a single variable to be used. 205 | */ 206 | 207 | bsTree.root.DFSTraverse { (node: BSNode) -> Int in 208 | 209 | let results = node.key! + node.height 210 | if node.height > 0 && node.key! == results { 211 | didFail = true 212 | } 213 | 214 | return results 215 | } 216 | 217 | XCTAssertFalse(didFail, "..closure update failed..") 218 | } 219 | 220 | 221 | 222 | //update avl values with closure function 223 | func traverseFormula(node: BSNode) -> Int { 224 | 225 | let results = node.key! + node.height 226 | if node.height > 0 && node.key! == results { 227 | XCTFail("closure update failed..") 228 | } 229 | 230 | return results 231 | } 232 | 233 | 234 | 235 | 236 | 237 | //MARK: Helper Functions 238 | 239 | 240 | 241 | //helper function - build and balance bst 242 | func buildBSTree(_ sequence: Array) -> () { 243 | 244 | 245 | //test for new instance 246 | let bsTest: BSTree = BSTree() 247 | XCTAssertNotNil(bsTest, "bst instance not created..") 248 | 249 | 250 | for item in sequence { 251 | print("adding \(item) to tree...") 252 | bsTest.append(element: item) 253 | } 254 | 255 | bsTest.root.DFSTraverse() 256 | 257 | XCTAssertTrue(bsTest.isTreeBalanced(for: bsTest.root), "tree is unbalanced..") 258 | } 259 | 260 | 261 | //helper function - build and balance bst 262 | func buildBSTree(_ sequence: Array) -> BSTree { 263 | 264 | 265 | //test for new instance 266 | let bsTest: BSTree = BSTree() 267 | XCTAssertNotNil(bsTest, "bst instance not created..") 268 | 269 | 270 | for item in sequence { 271 | print("adding \(item) to bst tree...") 272 | bsTest.append(element: item) 273 | } 274 | 275 | 276 | bsTest.root.DFSTraverse() 277 | 278 | 279 | XCTAssertTrue(bsTest.isTreeBalanced(for: bsTest.root), "tree is unbalanced..") 280 | 281 | 282 | return bsTest 283 | } 284 | 285 | 286 | 287 | 288 | //helper function - build specific model to be traversed with closures 289 | func buildClosureTree() -> BSTree { 290 | 291 | 292 | let bsTest: BSTree = BSTree() 293 | XCTAssertNotNil(bsTest, "bst instance not created..") 294 | 295 | 296 | //provide a balanced list 297 | let numberList : Array = [8, 5, 10, 3, 12, 9, 6, 16] 298 | 299 | 300 | for number in numberList { 301 | print("adding \(number) to avl tree...") 302 | bsTest.append(element: number) 303 | } 304 | 305 | 306 | XCTAssertTrue(bsTest.isTreeBalanced(for: bsTest.root), "tree is unbalanced..") 307 | 308 | 309 | return bsTest 310 | } 311 | 312 | 313 | 314 | } 315 | -------------------------------------------------------------------------------- /SwiftTests/BayesTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BayesTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/25/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import SwiftStructures 12 | 13 | 14 | class BayesTest: XCTestCase { 15 | 16 | //TODO: work in progress.. 17 | 18 | } 19 | -------------------------------------------------------------------------------- /SwiftTests/BlockTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BlockTest.swift 3 | // SwiftTests 4 | // 5 | // Created by Wayne Bishop on 2/4/18. 6 | // Copyright © 2018 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import SwiftStructures 12 | 13 | 14 | class BlockTest: XCTestCase { 15 | 16 | var bitcoin = Blockchain() 17 | 18 | var PeerA = Peer(with: "John Hobbs") 19 | var PeerB = Peer(with: "Frank Smith") 20 | var PeerC = Peer(with: "Albert Einstien") 21 | var PeerD = Peer(with: "Steve Jobs") 22 | 23 | 24 | override func setUp() { 25 | super.setUp() 26 | 27 | 28 | //add the vertices 29 | bitcoin.addVertex(element: PeerA) 30 | bitcoin.addVertex(element: PeerB) 31 | bitcoin.addVertex(element: PeerC) 32 | bitcoin.addVertex(element: PeerD) 33 | 34 | 35 | //add the edges 36 | bitcoin.addEdge(source: PeerA, neighbor: PeerB, weight: 1) 37 | bitcoin.addEdge(source: PeerA, neighbor: PeerC, weight: 1) 38 | bitcoin.addEdge(source: PeerB, neighbor: PeerD, weight: 1) 39 | 40 | 41 | //simulate intended transactions 42 | PeerA.intent(with: PeerB, for: 12.95) 43 | PeerB.intent(with: PeerC, for: 5.00) 44 | PeerC.intent(with: PeerD, for: 10.00) 45 | PeerB.intent(with: PeerD, for: 4.95) 46 | } 47 | 48 | 49 | 50 | //miners monitor the peer network for intended transactions 51 | func testPollForExchanges() { 52 | 53 | let miner = Blockchain.Miner() 54 | miner.poll(startingv: PeerA, network: bitcoin) 55 | 56 | 57 | bitcoin.broadcast(to: &PeerA) 58 | bitcoin.broadcast(to: &PeerB) 59 | bitcoin.broadcast(to: &PeerC) 60 | bitcoin.broadcast(to: &PeerD) 61 | 62 | } 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /SwiftTests/ClosureTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClosureTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 6/1/15. 6 | // Copyright (c) 2015 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | @testable import SwiftStructures 13 | 14 | 15 | class ClosureTest: XCTestCase { 16 | 17 | var numberList: Array! 18 | 19 | override func setUp() { 20 | super.setUp() 21 | numberList = [8, 5, 2, 10, 9, 7] 22 | } 23 | 24 | 25 | /* 26 | notes: This test class mimics the map & filter array 27 | functions found in the Swift standard library. Optimized for linked lists, each test 28 | demonstrates the nessesary syntax to implement a closure as an inline expression or standard function. 29 | See additional closure examples with GraphTest.swift and AVLTest.swift. 30 | */ 31 | 32 | 33 | //MARK: filter closures 34 | 35 | 36 | //filter based on expression 37 | func testLinkFilterExpression() { 38 | 39 | let linkedList: LinkedList = self.buildLinkedList() 40 | 41 | 42 | //inline closure expression 43 | let results: LinkedList! = linkedList.filter { (node: LLNode) -> Bool in 44 | return node.key! > 5 45 | } 46 | 47 | //display filtered results 48 | results.printAllKeys() 49 | 50 | if results.count == linkedList.count { 51 | XCTFail("linked list not filtered..") 52 | } 53 | 54 | 55 | } 56 | 57 | 58 | //filter based on function 59 | func testLinkFilterFunction() { 60 | 61 | let linkedList: LinkedList = self.buildLinkedList() 62 | 63 | //pass formula as parameter 64 | let results: LinkedList! = linkedList.filter(filterFormula) 65 | 66 | //print results 67 | results.printAllKeys() 68 | 69 | if results.count == linkedList.count { 70 | XCTFail("linked list not filtered..") 71 | } 72 | 73 | 74 | } 75 | 76 | 77 | 78 | //MARK: map closures 79 | 80 | 81 | //map based on expression 82 | func testLinkMapExpression() { 83 | 84 | let linkedList: LinkedList = self.buildLinkedList() 85 | 86 | //inline closure expression 87 | let results: LinkedList = linkedList.map { (node: LLNode) -> Int in 88 | 89 | var value: Int = 0 90 | 91 | if let key = node.key { 92 | 93 | //evaluate based on switch 94 | switch key { 95 | case 0..<5: 96 | value = key * 2 97 | case 5...10: 98 | value = key * 3 99 | default: 100 | value = key 101 | } 102 | } 103 | 104 | return value 105 | 106 | } //end closure 107 | 108 | 109 | //print results 110 | results.printAllKeys() 111 | 112 | 113 | //iterate and compare values 114 | for s in 0.. = self.buildLinkedList() 135 | 136 | //pass formula as parameter 137 | let results: LinkedList! = linkedList.map(mapFormula) 138 | 139 | //print results 140 | results.printAllKeys() 141 | 142 | 143 | //iterate and compare values 144 | for s in 0..) -> Bool { 162 | return node.key! > 5 163 | } 164 | 165 | 166 | 167 | //function to be passed as a parameter 168 | func mapFormula(node: LLNode) -> Int { 169 | 170 | var value: Int = 0 171 | 172 | if let key = node.key { 173 | 174 | //evaluate based on switch 175 | switch key { 176 | case 0..<5: 177 | value = key * 2 178 | case 5...10: 179 | value = key * 3 180 | default: 181 | value = key 182 | } 183 | } 184 | 185 | return value 186 | } 187 | 188 | 189 | //helper method to build list 190 | func buildLinkedList() ->LinkedList! { 191 | 192 | 193 | //create a new instance 194 | let linkedList: LinkedList = LinkedList() 195 | 196 | 197 | //append list items 198 | for number in numberList { 199 | linkedList.append(element: number) 200 | } 201 | 202 | 203 | if (linkedList.count != numberList.count) { 204 | XCTFail("linked list count doesn't match number list..") 205 | return nil 206 | } 207 | 208 | return linkedList 209 | 210 | 211 | } 212 | 213 | 214 | 215 | } 216 | -------------------------------------------------------------------------------- /SwiftTests/DelegateTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DelegateTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 5/16/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import SwiftStructures 12 | 13 | 14 | class DelegateTest: XCTestCase { 15 | 16 | override func setUp() { 17 | super.setUp() 18 | 19 | } 20 | 21 | //test delegation design pattern 22 | func testDelegatePattern() { 23 | 24 | let example = Delegation() 25 | example.processContent(withElement: 5) 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /SwiftTests/FibTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MathTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 10/29/15. 6 | // Copyright © 2015 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | 12 | /* 13 | note: algorithms associated directly with the Int.swift 14 | class extension. 15 | */ 16 | 17 | 18 | @testable import SwiftStructures 19 | 20 | 21 | class FibTest: XCTestCase { 22 | 23 | 24 | var count: Int = 0 25 | 26 | 27 | override func setUp() { 28 | super.setUp() 29 | } 30 | 31 | 32 | //MARK: Sequence Based 33 | 34 | 35 | //iterative technique 36 | func testFibonnaci() { 37 | 38 | let positions: Int = 4 39 | let results = positions.fibNormal() 40 | 41 | //test results 42 | buildResultsTest(results) 43 | } 44 | 45 | 46 | 47 | //recursive technique 48 | func testFibRecursive() { 49 | 50 | var positions: Int = 4 51 | let results = positions.fibRecursive() 52 | 53 | 54 | //test results 55 | buildResultsTest(results) 56 | } 57 | 58 | 59 | 60 | //closure option 61 | func testFibClosure() { 62 | 63 | 64 | let positions: Int = 4 65 | 66 | let results = positions.fibClosure { (sequence: Array!) -> Int in 67 | 68 | //initialize and set formula 69 | let i: Int = sequence.count 70 | let total: Int = sequence[i - 1] + sequence[i - 2] 71 | 72 | return total 73 | 74 | } 75 | 76 | //test results 77 | buildResultsTest(results) 78 | 79 | } 80 | 81 | 82 | //MARK: Single Answer 83 | 84 | 85 | 86 | func testFibExponential() { 87 | 88 | let positions: Int = 4 89 | let result = fibExponential(n: positions) 90 | 91 | print("the result is \(result)..") 92 | print("count is: \(count)") 93 | 94 | } 95 | 96 | 97 | 98 | func testFibMemoized() { 99 | 100 | let positions: Int = 4 101 | let result = positions.fibMemoized() 102 | 103 | //test trivial condition 104 | if result < 2 { 105 | XCTFail("Test failed: fib sequence not calculated..") 106 | } 107 | 108 | } 109 | 110 | 111 | 112 | 113 | //MARK: Helper Functions 114 | 115 | 116 | 117 | //helper function - test results validity 118 | func buildResultsTest(_ r: Array!) { 119 | 120 | 121 | if r == nil { 122 | XCTFail("fibonnaci test failed..") 123 | } 124 | 125 | 126 | //check calcuated answer against basic formula.. 127 | if r[r.endIndex - 1] != r[r.endIndex - 2] + r[r.endIndex - 3] { 128 | XCTFail("fibonnaci test failed..") 129 | } 130 | 131 | } 132 | 133 | 134 | 135 | /* 136 | notes: function included for demonstration purposes and should not be 137 | considered as best practice. 138 | */ 139 | 140 | func fibExponential(n: Int) -> Int { 141 | 142 | print("fibExponential called..") 143 | 144 | count += 1 145 | 146 | if n == 0 { 147 | return 0 148 | } 149 | if n <= 2 { 150 | return 1 151 | } 152 | 153 | return fibExponential(n: n-1) + fibExponential(n: n-2) 154 | } 155 | 156 | 157 | } 158 | -------------------------------------------------------------------------------- /SwiftTests/GraphTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GraphsTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/19/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | @testable import SwiftStructures 13 | 14 | 15 | /* 16 | unit test cases specific to graph algorithms 17 | to test your own graph, replace the vertices and edges. 18 | */ 19 | 20 | class GraphTest: XCTestCase { 21 | 22 | var testGraph: Graph = Graph() 23 | 24 | var vertexA = Vertex(with: "A") 25 | var vertexB = Vertex(with: "B") 26 | var vertexC = Vertex(with: "C") 27 | var vertexD = Vertex(with: "D") 28 | var vertexE = Vertex(with: "E") 29 | 30 | 31 | //called before each test invocation 32 | override func setUp() { 33 | super.setUp() 34 | 35 | /* add the vertices */ 36 | 37 | testGraph.addVertex(element: vertexA) 38 | testGraph.addVertex(element: vertexB) 39 | testGraph.addVertex(element: vertexC) 40 | testGraph.addVertex(element: vertexD) 41 | testGraph.addVertex(element: vertexE) 42 | 43 | 44 | /* connect the vertices with weighted edges */ 45 | 46 | testGraph.addEdge(source: vertexA, neighbor: vertexD, weight: 4) 47 | testGraph.addEdge(source: vertexA, neighbor: vertexB, weight: 1) 48 | testGraph.addEdge(source: vertexB, neighbor: vertexD, weight: 5) 49 | testGraph.addEdge(source: vertexB, neighbor: vertexC, weight: 2) 50 | testGraph.addEdge(source: vertexD, neighbor: vertexE, weight: 8) 51 | 52 | } 53 | 54 | 55 | //validate neighbor association 56 | func testVertexNeighbors() { 57 | 58 | neighborTest(of: vertexA, with: vertexD) 59 | neighborTest(of: vertexA, with: vertexB) 60 | neighborTest(of: vertexB, with: vertexD) 61 | neighborTest(of: vertexB, with: vertexC) 62 | neighborTest(of: vertexD, with: vertexE) 63 | } 64 | 65 | 66 | 67 | //find the shortest path using heapsort operations - O(1) 68 | func testDijkstraWithHeaps() { 69 | 70 | let sourceVertex = vertexA 71 | let destinationVertex = vertexE 72 | 73 | 74 | let shortestPath: Path! = testGraph.processDijkstraWithHeap(sourceVertex, destination: destinationVertex) 75 | XCTAssertNotNil(shortestPath, "shortest path not found..") 76 | 77 | printPath(shortestPath) 78 | } 79 | 80 | 81 | 82 | 83 | //find the shortest path based on two non-negative edge weights - O(n) 84 | func testDijkstra() { 85 | 86 | let sourceVertex = vertexA 87 | let destinationVertex = vertexE 88 | 89 | 90 | let shortestPath: Path! = testGraph.processDijkstra(sourceVertex, destination: destinationVertex) 91 | XCTAssertNotNil(shortestPath, "shortest path not found..") 92 | 93 | printPath(shortestPath) 94 | 95 | 96 | } 97 | 98 | 99 | //MARK: Closures and traversals 100 | 101 | 102 | //breadth-first search 103 | func testBFSTraverse() { 104 | testGraph.traverse(vertexA) 105 | } 106 | 107 | 108 | //breadth-first search with function 109 | func testBFSTraverseFunction() { 110 | testGraph.traverse(vertexA, formula: traverseFormula) 111 | } 112 | 113 | 114 | 115 | //breadth-first search with closure expression 116 | func testBFSTraverseExpression() { 117 | 118 | /* 119 | notes: the inout parameter is passed by reference. 120 | As a result, no return type is required. Also note the trailing closure syntax. 121 | */ 122 | 123 | testGraph.traverse(vertexA) { ( node: inout Vertex) -> () in 124 | 125 | node.visited = true 126 | print("traversed vertex: \(node.key)..") 127 | 128 | } 129 | 130 | 131 | } 132 | 133 | 134 | 135 | //closure function passed as parameter 136 | func traverseFormula(node: inout Vertex) -> () { 137 | 138 | /* 139 | notes: the inout parameter is passed by reference. 140 | As a result, no return type is required. 141 | */ 142 | 143 | node.visited = true 144 | print("traversed vertex: \(node.key)..") 145 | } 146 | 147 | 148 | 149 | 150 | //MARK: - Helper function 151 | 152 | 153 | //check for membership 154 | func neighborTest(of source: Vertex, with neighbor: Vertex) { 155 | 156 | 157 | //add unvisited vertices to the queue 158 | for e in source.neighbors { 159 | if (e.neighbor.key == neighbor.key) { 160 | return 161 | } 162 | } 163 | 164 | XCTFail("vertex \(neighbor.key) is not a neighbor of vertex \(source.key)") 165 | 166 | } 167 | 168 | 169 | //reverse a path data structure 170 | func printPath(_ shortestPath: Path!) { 171 | 172 | 173 | var reversedPath: Path! = Path() 174 | var current: Path! = Path() 175 | 176 | 177 | //reverse the sequence of paths 178 | reversedPath = testGraph.reversePath(shortestPath, source: vertexA) 179 | current = reversedPath 180 | 181 | 182 | //iterate and print each path sequence 183 | while (current != nil) { 184 | print("The path is : \(current.destination.key) with a total of : \(current.total)..") 185 | current = current.previous 186 | } 187 | 188 | 189 | 190 | } 191 | 192 | 193 | 194 | } //end class 195 | -------------------------------------------------------------------------------- /SwiftTests/HashTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 7/6/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import SwiftStructures 12 | 13 | 14 | class HashTest: XCTestCase { 15 | 16 | 17 | override func setUp() { 18 | super.setUp() 19 | } 20 | 21 | 22 | //test strings 23 | func testStringList() { 24 | 25 | 26 | /* 27 | note: each element has its own potential 'slot' in the 28 | hash list. In this scenario, the hash table algorithm will 29 | implement 'separate chaining' to support 'hash collisions'. 30 | */ 31 | 32 | //new string list 33 | let slist = HashTable(capacity: 3) 34 | 35 | 36 | _ = slist.insert("Wayne Bishop") 37 | _ = slist.insert("Frank Smith") 38 | _ = slist.insert("Jennifer Hobbs") 39 | _ = slist.insert("Tim Cook") 40 | _ = slist.insert("Steve Jobs") 41 | _ = slist.insert("Wayne Bishop") //should produce collision 42 | _ = slist.insert("Larry Page") 43 | _ = slist.insert("Albert Einstien") 44 | 45 | 46 | //test list compliance 47 | XCTAssertTrue(slist.contains("Frank Smith"), "hash table element not found..") 48 | } 49 | 50 | 51 | //test verticies - custom 52 | func testVertexList() { 53 | 54 | 55 | let testVertex: Vertex = Vertex() 56 | testVertex.key = "A" 57 | 58 | let vList: HashTable = HashTable(capacity: 10) 59 | _ = vList.insert(testVertex) 60 | 61 | 62 | //test list compliance 63 | XCTAssertTrue(vList.contains("A"), "hash table element not found..") 64 | 65 | } 66 | 67 | 68 | //test floats 69 | func testMissingList() { 70 | 71 | 72 | //new float list 73 | let fList = HashTable(capacity: 5) 74 | 75 | _ = fList.insert(10.2) 76 | _ = fList.insert(8.6) 77 | 78 | //element doesn't exist 79 | XCTAssertFalse(fList.contains(3.7), "hash table element not found..") 80 | 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /SwiftTests/HeapTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeapTest.swift 3 | // SwiftTests 4 | // 5 | // Created by Wayne Bishop on 9/14/17. 6 | // Copyright © 2017 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import SwiftStructures 12 | 13 | 14 | class HeapTest: XCTestCase { 15 | 16 | 17 | let numbers: Array = [5, 3, 7, 1, 9, 8] 18 | let letters: [Character] = ["E", "x", "a", "m", "p", "l", "e"] 19 | 20 | 21 | override func setUp() { 22 | super.setUp() 23 | } 24 | 25 | 26 | //MARK: Numeric Tests 27 | 28 | 29 | func testNumericMinHeap() { 30 | 31 | 32 | let minHeap = Heap() 33 | 34 | 35 | //heapify 36 | for item in numbers { 37 | minHeap.enQueue(item) 38 | } 39 | 40 | //test for min heap property 41 | XCTAssertTrue(minHeap.peek() == numbers.min(), "test failed: array structure violates min-heap property") 42 | 43 | } 44 | 45 | 46 | //test for max-heap property 47 | func testNumericMaxHeap() { 48 | 49 | let maxHeap = Heap(type: .Max) 50 | 51 | 52 | //heapify 53 | for item in numbers { 54 | maxHeap.enQueue(item) 55 | } 56 | 57 | //test for min heap property 58 | XCTAssertTrue(maxHeap.peek() == numbers.max(), "test failed: array structure violates max-heap property") 59 | 60 | } 61 | 62 | 63 | //MARK: Character Tests 64 | 65 | 66 | func testCharacterMinHeap() { 67 | 68 | let minHeap = Heap() 69 | 70 | 71 | //heapify 72 | for item in letters { 73 | minHeap.enQueue(item) 74 | } 75 | 76 | //test for min heap property 77 | XCTAssertTrue(minHeap.peek() == letters.min(), "test failed: array structure violates min heap property") 78 | 79 | } 80 | 81 | 82 | 83 | func testCharacterMaxHeap() { 84 | 85 | let maxHeap = Heap(type: .Max) 86 | 87 | 88 | //heapify 89 | for item in letters { 90 | maxHeap.enQueue(item) 91 | } 92 | 93 | //test for max heap property 94 | XCTAssertTrue(maxHeap.peek() == letters.max(), "test failed: array structure violates max-heap property") 95 | 96 | } 97 | 98 | 99 | 100 | } 101 | -------------------------------------------------------------------------------- /SwiftTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /SwiftTests/LearningTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LearningTest.swift 3 | // SwiftTests 4 | // 5 | // Created by Wayne Bishop on 10/22/18. 6 | // Copyright © 2018 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import SwiftStructures 12 | 13 | 14 | class LearningTest: XCTestCase { 15 | 16 | override func setUp() { 17 | super.setUp() 18 | } 19 | 20 | 21 | //establish a positive test 22 | func testAEClassifierAccurate() { 23 | 24 | let statement = "The solar system has eight planets" 25 | 26 | guard let result: AEClassifierResult = self.buildAELearningModel(with: statement) else { 27 | print("test failed: no predicted value for AEClassifier..") 28 | XCTFail() 29 | return 30 | } 31 | 32 | 33 | if result != "accurate" { 34 | print("accurate statement not identified by AEClassifier..") 35 | XCTFail() 36 | return 37 | } 38 | 39 | 40 | } 41 | 42 | 43 | //establish a negative test 44 | func testAEClassifierExaggeration() { 45 | 46 | let statement = "It always rains in Seattle" 47 | 48 | guard let result: AEClassifierResult = self.buildAELearningModel(with: statement) else { 49 | print("test failed: no predicted value for AEClassifier..") 50 | XCTFail() 51 | return 52 | } 53 | 54 | 55 | if result != "exaggeration" { 56 | print("exaggerated statement not identified by AEClassifier..") 57 | XCTFail() 58 | return 59 | } 60 | 61 | } 62 | 63 | 64 | 65 | 66 | //helper function - build machine learning model 67 | func buildAELearningModel(with prediction: String) -> AEClassifierResult? { 68 | 69 | //create a new learning instance using AEClassifier 70 | let learning = Learning() 71 | let results = learning.AEPredict(using: prediction) 72 | 73 | return results 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /SwiftTests/LinkedTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkedTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/23/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | @testable import SwiftStructures 13 | 14 | 15 | //struct for testing indicies 16 | struct keyIndex { 17 | 18 | public var key: Int 19 | public var index: Int 20 | } 21 | 22 | 23 | 24 | class LinkedTest: XCTestCase { 25 | 26 | var numberList : Array! 27 | 28 | 29 | override func setUp() { 30 | super.setUp() 31 | numberList = [8, 2, 10, 9, 7, 5] 32 | } 33 | 34 | //retrieve specific links 35 | func testLinkAtIndex() { 36 | 37 | 38 | let list = buildLinkedList() 39 | let nodecount: Int = list.count 40 | 41 | 42 | //test lower-bound 43 | let lbound = list[0] 44 | if ((lbound == nil) || (lbound?.key != numberList[0])) { 45 | XCTFail("lowest bound retrieve fail..") 46 | } 47 | 48 | 49 | //upper bound 50 | let ubound = list[nodecount - 1] 51 | if ((ubound == nil) || (ubound?.key != numberList[nodecount - 1])) { 52 | XCTFail("upper bound retrieve fail..") 53 | } 54 | 55 | 56 | //establish random index 57 | let range: UInt32 = UInt32(numberList.count) 58 | let randomIndex = Int(arc4random_uniform(range)) 59 | 60 | 61 | //retrieve random index 62 | let randomlink = list[randomIndex] 63 | if ((randomlink == nil) || (randomlink?.key != numberList[randomIndex])) { 64 | XCTFail("random index retrieve fail..") 65 | } 66 | 67 | } 68 | 69 | 70 | 71 | 72 | //test nodes at a specific index 73 | func testAddLinkAtIndex() { 74 | 75 | 76 | //create list and test pair 77 | let list = buildLinkedList() 78 | let testPair: keyIndex = keyIndex(key: 4, index: 3) 79 | 80 | 81 | list.insert(testPair.key, at: testPair.index) 82 | list.printAllKeys() 83 | 84 | 85 | let current = list[testPair.index] 86 | 87 | //test condition 88 | if current == nil || current?.key != testPair.key { 89 | XCTFail("linked list addition at index failed..") 90 | } 91 | 92 | 93 | //remove test item 94 | list.remove(at: testPair.index) 95 | list.printAllKeys() 96 | 97 | 98 | //retrieve value at same position 99 | let removed = list[testPair.index] as LLNode? 100 | 101 | 102 | if removed == nil || removed?.key == testPair.key { 103 | XCTFail("test failed: removed linked list element not found") 104 | } 105 | 106 | 107 | } //end function 108 | 109 | 110 | 111 | 112 | //reverse a linked list 113 | func testReverseLinkedList() { 114 | 115 | let list = buildLinkedList() 116 | 117 | 118 | //find (subscript) syntax 119 | guard let flink = list[0] else { 120 | XCTFail("link for reversal not found..") 121 | return 122 | } 123 | 124 | //reverse the list 125 | list.reverse() 126 | list.printAllKeys() 127 | 128 | 129 | if let blink = list[0] { 130 | 131 | //evaluate keys 132 | if (flink.key == blink.key) { 133 | XCTFail("reversed list failed..") 134 | } 135 | } 136 | } 137 | 138 | 139 | 140 | //MARK: helper functions 141 | 142 | 143 | func buildLinkedList() ->LinkedList { 144 | 145 | let list = LinkedList() 146 | 147 | //append items 148 | for number in numberList { 149 | list.append(element: number) 150 | } 151 | 152 | 153 | list.printAllKeys() 154 | XCTAssertFalse(list.count != numberList.count, "test failed: linked list count doesn't match number list..") 155 | 156 | return list 157 | } 158 | 159 | } 160 | -------------------------------------------------------------------------------- /SwiftTests/QueueTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QueueTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 8/5/15. 6 | // Copyright (c) 2015 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SwiftStructures 11 | 12 | 13 | class QueueTest: XCTestCase { 14 | 15 | var numberList: Array! 16 | 17 | 18 | override func setUp() { 19 | super.setUp() 20 | numberList = [8, 2, 10, 9, 7, 5] 21 | } 22 | 23 | 24 | /* 25 | notes: This test class mimics the basic functionality of adding and removing queue items. 26 | The "times" closure expression used is a custom implementation and is not part 27 | of the core library. 28 | */ 29 | 30 | 31 | //test the deQueueing process 32 | func testDeQueue() { 33 | 34 | let q: Queue! = buildQueue() 35 | 36 | XCTAssertNotNil(q, "queue instance not present..") 37 | 38 | 39 | //deQueue list items.. 40 | numberList.count.times { (s: Int) -> Void in 41 | print("the queued item is \(q.peek() as Int?)") 42 | print ("count is: \(q.count)") 43 | _ = q.deQueue() 44 | } 45 | 46 | 47 | //check for queued items 48 | XCTAssertTrue(q.count == 0, "deQueue process failed..") 49 | XCTAssertTrue(q.isEmpty(), "queue isEmpty() process failed..") 50 | 51 | 52 | } 53 | 54 | 55 | //MARK: helper methods 56 | 57 | func buildQueue() -> Queue! { 58 | 59 | let newq: Queue! = Queue() 60 | 61 | XCTAssertTrue(newq.count == 0, "new queue instance not created..") 62 | 63 | 64 | //build queue 65 | for s in numberList { 66 | newq.enQueue(s) 67 | print("count is: \(newq.count)") 68 | } 69 | 70 | 71 | 72 | //check equality 73 | if newq.count != numberList.count { 74 | XCTFail("queue build failed..") 75 | } 76 | 77 | return newq 78 | 79 | } 80 | 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /SwiftTests/QuickTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QuickTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 8/16/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import SwiftStructures 12 | 13 | 14 | class QuickTest: XCTestCase, Sortable { 15 | 16 | override func setUp() { 17 | super.setUp() 18 | } 19 | 20 | 21 | 22 | //best case - O(n log(n)) 23 | func testSplitQSort() { 24 | 25 | 26 | /* 27 | note: the order of unsorted numbers represents the best case because 28 | the last item in the collection (4) will be used as a initial pivot. 29 | As a result, the left and right partitions will be equally split. 30 | */ 31 | 32 | var sequence: Array = [7, 2, 1, 6, 8, 5, 3, 4] 33 | let results = sequence.quickSort() 34 | 35 | //evaluate results 36 | processQuickResults(with: results) 37 | } 38 | 39 | 40 | //worst case scenario - 41 | func testDecendingQSort() { 42 | 43 | var sequence: Array = [8, 7, 6, 5, 4, 3, 2, 1] 44 | let results = sequence.quickSort() 45 | 46 | //evaluate results 47 | processQuickResults(with: results) 48 | } 49 | 50 | 51 | func testAscendingQSort() { 52 | 53 | var sequence: Array = [1, 2, 3, 4, 5, 6, 7, 8] 54 | let results = sequence.quickSort() 55 | 56 | //evaluate results 57 | processQuickResults(with: results) 58 | } 59 | 60 | 61 | 62 | //test with random numbers 63 | func testRandomNumberQSort() { 64 | 65 | var sequence: Array = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3] 66 | 67 | let results = sequence.quickSort() 68 | 69 | //evaluate results 70 | processQuickResults(with: results) 71 | } 72 | 73 | 74 | //test example with comparable dates 75 | func testDatesQSort() { 76 | 77 | 78 | //create random dates - extension 79 | let pastdate: Date = "05-13-2016".datevalue 80 | let nowdate: Date = "12-12-2016".datevalue 81 | let futuredate: Date = "01-16-2017".datevalue 82 | 83 | 84 | var sequence: Array = [nowdate, futuredate, pastdate] 85 | let results = sequence.quickSort() 86 | 87 | 88 | //evaluate results 89 | processQuickResults(with: results) 90 | 91 | } 92 | 93 | 94 | //MARK: Helper function 95 | 96 | func processQuickResults(with sequence: Array) { 97 | print("quick sort results: \(sequence)") 98 | XCTAssertTrue(isSorted(sequence), "test failed: sequence not sorted: " + String(describing: sequence)) 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /SwiftTests/SortingTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinarySearchTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/23/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | @testable import SwiftStructures 13 | 14 | 15 | /* 16 | notes: this test class adopts the Sortable protocol. 17 | the isSorted function originates from the protocol extension. 18 | */ 19 | 20 | 21 | class SortingTest: XCTestCase, Sortable { 22 | 23 | 24 | //test input types for algorithms 25 | var numberList = [8, 2, 10, 9, 7, 5] 26 | var searchList = [0,4,7,9,13,16,34] 27 | var trivialNumberList = [1] 28 | var emptyNumberList: Array = [] 29 | var textList = ["Dog", "Cat", "Dinasour", "Lion", "Cheetah", "Gazelle", "Elephant", "Aardvark"] 30 | var triviaTextList = ["Dog"] 31 | var emptyTextList: Array = [] 32 | 33 | //string extension 34 | var dateList: Array = ["12-10-2016".datevalue, "12-08-2016".datevalue, "12-09-2016".datevalue] 35 | 36 | 37 | override func setUp() { 38 | super.setUp() 39 | } 40 | 41 | func testLongestSequence() { 42 | 43 | let list = [0,1,0,1,1,1,0,1,1,1,1,1] 44 | let results = list.longestSequence(of: 1) 45 | 46 | print("the longest sequence is \(results)") 47 | } 48 | 49 | 50 | //MARK: - Binary Search Algorithms 51 | 52 | 53 | func testBinarySearch() { 54 | 55 | var searchList = Array() 56 | let key: Int = 235 57 | 58 | 59 | //populate collection.. 60 | for number in 0...500 { 61 | searchList.append(number) 62 | } 63 | 64 | 65 | XCTAssertTrue(self.isSorted(searchList), "search list of values not sorted..") 66 | 67 | 68 | //perform test search 69 | XCTAssertTrue(searchList.binarySearch(forElement: key), "binary key value \(key) not found..") 70 | 71 | } 72 | 73 | 74 | func testBinaryNotFound() { 75 | 76 | let key: Int = 8 77 | 78 | //test for false positive 79 | XCTAssertFalse(searchList.binarySearch(forElement: key), "binary key value \(key) found..") 80 | } 81 | 82 | 83 | func testBinaryFound() { 84 | 85 | let key: Int = 9 86 | 87 | XCTAssertTrue(searchList.binarySearch(forElement: key), "binary key value \(key) not found..") 88 | } 89 | 90 | 91 | //MARK: General Sorting Algorithms 92 | 93 | 94 | func testInsertionSort() { 95 | 96 | XCTAssertTrue(isSorted(numberList.insertionSort())) 97 | XCTAssertTrue(isSorted(trivialNumberList.insertionSort())) 98 | XCTAssertTrue(isSorted(emptyNumberList.insertionSort())) 99 | XCTAssertTrue(isSorted(textList.insertionSort())) 100 | XCTAssertTrue(isSorted(triviaTextList.insertionSort())) 101 | XCTAssertTrue(isSorted(emptyTextList.insertionSort())) 102 | XCTAssert(isSorted(dateList.insertionSort())) 103 | } 104 | 105 | 106 | 107 | func testBubbleSort() { 108 | 109 | XCTAssertTrue(isSorted(numberList.bubbleSort())) 110 | XCTAssertTrue(isSorted(trivialNumberList.bubbleSort())) 111 | XCTAssertTrue(isSorted(emptyNumberList.bubbleSort())) 112 | XCTAssertTrue(isSorted(textList.bubbleSort())) 113 | XCTAssertTrue(isSorted(triviaTextList.bubbleSort())) 114 | XCTAssertTrue(isSorted(emptyTextList.bubbleSort())) 115 | XCTAssert(isSorted(dateList.bubbleSort())) 116 | 117 | } 118 | 119 | 120 | 121 | func testSelectionSort() { 122 | 123 | XCTAssertTrue(isSorted(numberList.selectionSort())) 124 | XCTAssertTrue(isSorted(trivialNumberList.selectionSort())) 125 | XCTAssertTrue(isSorted(emptyNumberList.selectionSort())) 126 | XCTAssertTrue(isSorted(textList.selectionSort())) 127 | XCTAssertTrue(isSorted(triviaTextList.selectionSort())) 128 | XCTAssertTrue(isSorted(emptyTextList.selectionSort())) 129 | XCTAssert(isSorted(dateList.selectionSort())) 130 | 131 | } 132 | 133 | 134 | } 135 | -------------------------------------------------------------------------------- /SwiftTests/StackTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/1/15. 6 | // Copyright © 2015 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import SwiftStructures 12 | 13 | 14 | class StackTest: XCTestCase { 15 | 16 | var numberList: Array! 17 | 18 | override func setUp() { 19 | super.setUp() 20 | 21 | numberList = [8, 2, 10, 9, 1, 5] 22 | } 23 | 24 | 25 | 26 | //provides self-contained example of push function - essay example 27 | func testPushStack() { 28 | 29 | 30 | let myStack = Stack() 31 | XCTAssertTrue(myStack.count == 0, "test failed: count not initialized..") 32 | 33 | 34 | //build stack 35 | for s in numberList { 36 | myStack.push(withKey: s) 37 | print("item: \(s) added..") 38 | } 39 | 40 | XCTAssertTrue(myStack.count == numberList.count, "test failed: stack count does not match..") 41 | } 42 | 43 | 44 | 45 | func testPopStack() { 46 | 47 | 48 | //build stack - helper function 49 | let myStack: Stack = self.buildStack() 50 | 51 | 52 | if myStack.count == 0 { 53 | XCTFail("test failed: no stack items available..") 54 | } 55 | 56 | 57 | for _ in stride(from: myStack.count, through: 0, by: -1) { 58 | print("stack item is: \(String(describing: myStack.peek().key)). stack count: \(myStack.count)") 59 | myStack.pop() 60 | } 61 | 62 | 63 | XCTAssertTrue(myStack.isEmpty(), "test failed: stack structured not emptied..") 64 | 65 | } 66 | 67 | 68 | 69 | //MARK: helper methods 70 | 71 | func buildStack() -> Stack! { 72 | 73 | let newStack: Stack = Stack() 74 | XCTAssertTrue(newStack.count == 0, "test failed: count not initialized..") 75 | 76 | 77 | //build stack 78 | for s in numberList { 79 | newStack.push(withKey: s) 80 | print("item: \(s) added..") 81 | } 82 | 83 | 84 | print("stack count is: \(newStack.count)") 85 | 86 | 87 | return newStack 88 | 89 | } 90 | 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /SwiftTests/StructureTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StructuresTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 9/17/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | @testable import SwiftStructures 13 | 14 | 15 | class StructureTest: XCTestCase { 16 | 17 | 18 | //MARK: Node objects 19 | 20 | 21 | func testNode() { 22 | let testNode = Node() 23 | 24 | XCTAssertNotNil(testNode, "instance not initialized..") 25 | XCTAssertNil(testNode.key, "key not initialized..") 26 | XCTAssertNil(testNode.next, "next instance not initialized..") 27 | } 28 | 29 | 30 | func testLLNode() { 31 | let testLLNode: LLNode = LLNode() 32 | 33 | XCTAssertNotNil(testLLNode, "instance not initialized..") 34 | XCTAssertNil(testLLNode.key, "key not initialized..") 35 | XCTAssertNil(testLLNode.next, "next node propety not initialized..") 36 | XCTAssertNil(testLLNode.previous, "previous node propety not initialized..") 37 | } 38 | 39 | 40 | 41 | //MARK: Graph objects 42 | 43 | 44 | func testVertex() { 45 | 46 | let testVertex: Vertex = Vertex() 47 | 48 | XCTAssertNotNil(testVertex, "instance not intialized..") 49 | XCTAssertFalse(testVertex.visited, "visited property not intialized..") 50 | 51 | 52 | //downcast to test for membership 53 | let neigborList: AnyObject = testVertex.neighbors as AnyObject 54 | if !(neigborList is Array) { 55 | XCTFail("neighborlist does not include array list of edges..") 56 | } 57 | 58 | } 59 | 60 | 61 | 62 | func testEdge() { 63 | 64 | let edgeTest: Edge = Edge() 65 | 66 | XCTAssertNotNil(edgeTest, "instance not initialized..") 67 | XCTAssertEqual(edgeTest.weight, 0, "edge weight not initialized..") 68 | 69 | let testVertex: AnyObject = edgeTest.neighbor as AnyObject 70 | if !(testVertex is Vertex) { 71 | XCTFail("edge vertex not intialized..") 72 | } 73 | 74 | } 75 | 76 | 77 | func testPath() { 78 | 79 | let pathTest: Path = Path() 80 | 81 | XCTAssertNotNil(pathTest, "instance not initialized..") 82 | XCTAssertNil(pathTest.previous, "path previous property not initialized..") 83 | XCTAssertTrue(pathTest.total == 0, "path total property not initialized..") 84 | 85 | let testVertex: AnyObject = pathTest.destination as AnyObject 86 | if !(testVertex is Vertex) { 87 | XCTFail("destination vertex not intialized..") 88 | } 89 | 90 | } 91 | 92 | 93 | 94 | func testBSNode() { 95 | 96 | let testNode = BSNode() 97 | 98 | XCTAssertNotNil(testNode, "instance not initialized..") 99 | XCTAssertNil(testNode.key, "key property not initialized..") 100 | XCTAssertNil(testNode.left, "left property not initialized..") 101 | XCTAssertNil(testNode.right, "right property not initialized..") 102 | 103 | } 104 | 105 | 106 | } 107 | -------------------------------------------------------------------------------- /SwiftTests/TrieTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TrieTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 10/14/14. 6 | // Copyright (c) 2014 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | @testable import SwiftStructures 13 | 14 | 15 | class TrieTest: XCTestCase { 16 | 17 | var testTrie = Trie() 18 | 19 | 20 | override func setUp() { 21 | super.setUp() 22 | 23 | XCTAssertNotNil(testTrie, "Trie instance not correctly intialized..") 24 | 25 | //add words to data structure 26 | testTrie.append(word: "Ball") 27 | testTrie.append(word: "Balls") 28 | testTrie.append(word: "Ballard") 29 | testTrie.append(word: "Bat") 30 | testTrie.append(word: "Bar") 31 | } 32 | 33 | 34 | 35 | /* 36 | the findWord algorithm will only return strings identified as words. For example, the prefix "Ba" has children, 37 | but only 2 are marked as final. Even though the phrase "Bal" is found in the trie, it is not 38 | identified as a word. 39 | */ 40 | 41 | func testFindWithPrefix() { 42 | 43 | guard let list = testTrie["Ba"] else { 44 | XCTFail("test failed: no words found..") 45 | return 46 | } 47 | 48 | for word in list { 49 | print("\(word) found in trie..") 50 | } 51 | } 52 | 53 | 54 | 55 | 56 | //note: the findWord algorthim will identify both parents and children identified as words 57 | 58 | func testFindWithWord() { 59 | 60 | guard let list = testTrie["Ball"] else { 61 | XCTFail("test failed: no words found") 62 | return 63 | } 64 | 65 | for word in list { 66 | print("\(word) found in trie..") 67 | } 68 | 69 | } 70 | 71 | 72 | //testing false search results 73 | func testFindNoExist() { 74 | 75 | let keyword = "Barstool" 76 | 77 | //attempt to find word 78 | guard let _ = testTrie[keyword] else { 79 | return 80 | } 81 | 82 | XCTFail("test failed: \(keyword) incorrectly found in trie..") 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /SwiftTests/enumTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // enumTest.swift 3 | // SwiftStructures 4 | // 5 | // Created by Wayne Bishop on 4/25/16. 6 | // Copyright © 2016 Arbutus Software Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | 12 | @testable import SwiftStructures 13 | 14 | 15 | /* 16 | notes: this test class adopts the Sortable protocol. as a result, 17 | the isSorted function originates from the protocol extension. 18 | */ 19 | 20 | 21 | class enumsTest: XCTestCase, Sortable { 22 | 23 | 24 | let list = Algorithm.Elements([8, 2, 10, 9, 7, 5]) 25 | 26 | 27 | override func setUp() { 28 | super.setUp() 29 | } 30 | 31 | 32 | //model for insertion sort algorithm 33 | func testInsertModel() { 34 | 35 | let model = Algorithm.InsertionSort(list) 36 | self.buildEnumModel(withModel: model) 37 | } 38 | 39 | 40 | //model for insertion sort (with text) 41 | func testInsertTextModel() { 42 | 43 | let textList = Algorithm.Elements(["Dog", "Cat", "Dinasour", "Lion", "Cheetah", "Elephant", "Aardvark"]) 44 | 45 | let model = Algorithm.InsertionSort(textList) 46 | self.buildEnumModel(withModel: model) 47 | 48 | } 49 | 50 | 51 | //model for bubble sort algorithm 52 | func testBubbleModel() { 53 | 54 | let model = Algorithm.BubbleSort(list) 55 | self.buildEnumModel(withModel: model) 56 | } 57 | 58 | 59 | //model for selection sort algorithm 60 | func testSelectionModel() { 61 | 62 | let model = Algorithm.SelectionSort(list) 63 | self.buildEnumModel(withModel: model) 64 | } 65 | 66 | 67 | 68 | //MARK: Helper Function 69 | 70 | 71 | //helper function - test enum model 72 | func buildEnumModel(withModel model: Algorithm) { 73 | 74 | let enumModel = EnumModel() 75 | let results = enumModel.evaluate(withModel: model) 76 | XCTAssertTrue(self.isSorted(results!), "list values incorrectly sorted..") 77 | } 78 | 79 | 80 | } 81 | 82 | 83 | 84 | 85 | 86 | --------------------------------------------------------------------------------