├── .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 |
--------------------------------------------------------------------------------