From eb54bc8544f0d482336878e211269ea43da9a7a7 Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Mon, 30 Jan 2017 11:38:32 +0100 Subject: [PATCH 001/327] Add Simulated annealing --- Simulated annealing/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Simulated annealing/README.md diff --git a/Simulated annealing/README.md b/Simulated annealing/README.md new file mode 100644 index 000000000..bee8ffe94 --- /dev/null +++ b/Simulated annealing/README.md @@ -0,0 +1 @@ +# Simulated annealing From a6afbc107e25b96bdb86b9186f4a5794046b004b Mon Sep 17 00:00:00 2001 From: Mike Taghavi Date: Mon, 30 Jan 2017 18:18:50 +0100 Subject: [PATCH 002/327] Initial --- Simulated annealing/README.md | 32 ++++ Simulated annealing/simann.swift | 105 +++++++++++ Simulated annealing/simann_example.swift | 222 +++++++++++++++++++++++ 3 files changed, 359 insertions(+) create mode 100644 Simulated annealing/simann.swift create mode 100644 Simulated annealing/simann_example.swift diff --git a/Simulated annealing/README.md b/Simulated annealing/README.md index bee8ffe94..e7fe75778 100644 --- a/Simulated annealing/README.md +++ b/Simulated annealing/README.md @@ -1 +1,33 @@ # Simulated annealing + +Simulated Annealing is a nature inspired global optimization technique and a metaheuristic to approximate global maxima in a (often discrete)large search space. The name comes from the process of annealing in metallurgy where a material is heated and cooled down under controlled conditions in order to improve its strength and durabilility. The objective is to find a minimum cost solution in the search space by exploiting properties of a thermodynamic system. +Unlike hill climbing techniques which usually gets stuck in a local maxima ( downward moves are not allowed ), simulated annealing can escape local maxima. The interesting property of simulated annealing is that probability of allowing downward moves is high at the high temperatures and gradually reduced as it cools down. In other words, high temperature relaxes the acceptance criteria for the search space and triggers chaotic behavior of acceptance function in the algorithm (e.x initial/high temperature stages) which should make it possible to escape from local maxima and cooler temperatures narrows it and focuses on improvements. + +Pseucocode + + Input: initial, temperature, coolingRate, acceptance + Output: Sbest + Scurrent <- CreateInitialSolution(initial) + Sbest <- Scurrent + while temperature is not minimum: + Snew <- FindNewSolution(Scurrent) + if acceptance(Energy(Scurrent), Energy(Snew), temperature) > Rand(): + Scurrent = Snew + if Energy(Scurrent) < Energy(Sbest): + Sbest = Scurrent + temperature = temperature * (1-coolingRate) + +Common acceptance criteria : P(accept) <- exp((e-ne)/T) where + e is the current energy ( current solution ), + ne is new energy ( new solution ), + T is current temperature. + + +We use this algorithm to solve a Travelling salesman problem instance with 20 cities. The code is in `simann_example.swift` + +#See also + +[Simulated annealing on Wikipedia](https://en.wikipedia.org/wiki/Simulated_annealing) +[Travelling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) + +Written for Swift Algorithm Club by [Mike Taghavi](https://github.com/mitghi) diff --git a/Simulated annealing/simann.swift b/Simulated annealing/simann.swift new file mode 100644 index 000000000..8adfbf817 --- /dev/null +++ b/Simulated annealing/simann.swift @@ -0,0 +1,105 @@ +// The MIT License (MIT) +// Copyright (c) 2017 Mike Taghavi (mitghi[at]me.com) +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#if os(OSX) + import Foundation +#elseif os(Linux) + import Glibc +#endif + +public extension Double { + public static func random(_ lower: Double, _ upper: Double) -> Double { + #if os(OSX) + return (Double(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower + #elseif os(Linux) + return (Double(random()) / 0xFFFFFFFF) * (upper - lower) + lower + #endif + } +} + +protocol Clonable { + init(current: Self) +} + +// MARK: - create a clone from instance + +extension Clonable { + func clone() -> Self { + return Self.init(current: self) + } +} + +protocol SAObject: Clonable { + var count: Int { get } + func randSwap(a: Int, b: Int) + func currentEnergy() -> Double + func shuffle() +} + +// MARK: - create a new copy of elements + +extension Array where Element: Clonable { + func clone() -> Array { + var newArray = Array() + for elem in self { + newArray.append(elem.clone()) + } + + return newArray + } +} + +typealias AcceptanceFunc = (Double, Double, Double) -> Double + +func SimulatedAnnealing(initial: T, temperature: Double, coolingRate: Double, acceptance: AcceptanceFunc) -> T { + // Step 1: + // Calculate the initial feasible solution based on a random permutation. + // Set best and current solutions to initial solution + + var temp: Double = temperature + var currentSolution = initial.clone() + currentSolution.shuffle() + var bestSolution = currentSolution.clone() + + // Step 2: + // Repeat while the system is still hot + // Randomly modify the current solution by swapping its elements + // Randomly decide if the new solution ( neighbor ) is acceptable and set current solution accordingly + // Update the best solution *iff* it had improved ( lower energy = improvement ) + // Reduce temperature + + while temp > 1 { + let newSolution: T = currentSolution.clone() + let pos1: Int = Int(arc4random_uniform(UInt32(newSolution.count))) + let pos2: Int = Int(arc4random_uniform(UInt32(newSolution.count))) + newSolution.randSwap(a: pos1, b: pos2) + let currentEnergy: Double = currentSolution.currentEnergy() + let newEnergy: Double = newSolution.currentEnergy() + + if acceptance(currentEnergy, newEnergy, temp) > Double.random(0, 1) { + currentSolution = newSolution.clone() + } + if currentSolution.currentEnergy() < bestSolution.currentEnergy() { + bestSolution = currentSolution.clone() + } + + temp *= 1-coolingRate + } + + return bestSolution +} diff --git a/Simulated annealing/simann_example.swift b/Simulated annealing/simann_example.swift new file mode 100644 index 000000000..a0dfaa19a --- /dev/null +++ b/Simulated annealing/simann_example.swift @@ -0,0 +1,222 @@ +// The MIT License (MIT) +// Copyright (c) 2017 Mike Taghavi (mitghi[at]me.com) +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#if os(OSX) + import Foundation +#elseif os(Linux) + import Glibc +#endif + +public extension Double { + + public static func random(_ lower: Double, _ upper: Double) -> Double { + #if os(OSX) + return (Double(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower + #elseif os(Linux) + return (Double(random()) / 0xFFFFFFFF) * (upper - lower) + lower + #endif + } +} + +protocol Clonable { + init(current: Self) +} + +extension Clonable { + func clone() -> Self { + return Self.init(current: self) + } +} + +protocol SAObject: Clonable { + var count: Int { get } + func randSwap(a: Int, b: Int) + func currentEnergy() -> Double + func shuffle() +} + +// MARK: - create a new copy of elements + +extension Array where Element: Clonable { + func clone() -> Array { + var newArray = Array() + for elem in self { + newArray.append(elem.clone()) + } + + return newArray + } +} + +typealias Points = [Point] +typealias AcceptanceFunc = (Double, Double, Double) -> Double + +class Point: Clonable { + var x: Int + var y: Int + + init(x: Int, y: Int) { + self.x = x + self.y = y + } + + required init(current: Point){ + self.x = current.x + self.y = current.y + } +} + +// MARK: - string representation + +extension Point: CustomStringConvertible { + public var description: String { + return "Point(\(x), \(y))" + } +} + +// MARK: - return distance between two points using operator '<->' + +infix operator <->: AdditionPrecedence +extension Point { + static func <-> (left: Point, right: Point) -> Double { + let xDistance = (left.x - right.x) + let yDistance = (left.y - right.y) + + return Double(sqrt(Double((xDistance * xDistance) + (yDistance * yDistance)))) + } +} + + +class Tour: SAObject { + var tour: Points + var energy: Double = 0.0 + var count: Int { + get { + return self.tour.count + } + } + + init(points: Points){ + self.tour = points.clone() + } + + required init(current: Tour) { + self.tour = current.tour.clone() + } +} + +// MARK: - calculate current tour distance ( energy ). + +extension Tour { + func randSwap(a: Int, b: Int) -> Void { + let (cpos1, cpos2) = (self[a], self[b]) + self[a] = cpos2 + self[b] = cpos1 + } + + func shuffle() { + for i in stride(from: self.count - 1, through: 1, by: -1) { + let j = Int(arc4random()) % (i + 1) + if i != j { + swap(&self.tour[i], &self.tour[j]) + } + } + } + + func currentEnergy() -> Double { + if self.energy == 0 { + var tourEnergy: Double = 0.0 + for i in 0..destCity + tourEnergy = tourEnergy + e + + } + self.energy = tourEnergy + } + return self.energy + } + +} + +// MARK: - subscript to manipulate elements of Tour. + +extension Tour { + subscript(index: Int) -> Point { + get { + return self.tour[index] + } + set(newValue) { + self.tour[index] = newValue + } + } +} + +func SimulatedAnnealing(initial: T, temperature: Double, coolingRate: Double, acceptance: AcceptanceFunc) -> T { + var temp: Double = temperature + var currentSolution = initial.clone() + currentSolution.shuffle() + var bestSolution = currentSolution.clone() + print("Initial solution: ", bestSolution.currentEnergy()) + + while temp > 1 { + let newSolution: T = currentSolution.clone() + let pos1: Int = Int(arc4random_uniform(UInt32(newSolution.count))) + let pos2: Int = Int(arc4random_uniform(UInt32(newSolution.count))) + newSolution.randSwap(a: pos1, b: pos2) + let currentEnergy: Double = currentSolution.currentEnergy() + let newEnergy: Double = newSolution.currentEnergy() + + if acceptance(currentEnergy, newEnergy, temp) > Double.random(0, 1) { + currentSolution = newSolution.clone() + } + if currentSolution.currentEnergy() < bestSolution.currentEnergy() { + bestSolution = currentSolution.clone() + } + + temp *= 1-coolingRate + } + + print("Best solution: ", bestSolution.currentEnergy()) + return bestSolution +} + +let points: [Point] = [ + (60 , 200), (180, 200), (80 , 180), (140, 180), + (20 , 160), (100, 160), (200, 160), (140, 140), + (40 , 120), (100, 120), (180, 100), (60 , 80) , + (120, 80) , (180, 60) , (20 , 40) , (100, 40) , + (200, 40) , (20 , 20) , (60 , 20) , (160, 20) , + ].map{ Point(x: $0.0, y: $0.1) } + +let acceptance : AcceptanceFunc = { + (e: Double, ne: Double, te: Double) -> Double in + if ne < e { + return 1.0 + } + return exp((e - ne) / te) +} + +let result: Tour = SimulatedAnnealing(initial : Tour(points: points), + temperature : 100000.0, + coolingRate : 0.003, + acceptance : acceptance) From a794dec1522cd0df09b96a2d8744b261b8185f2a Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 30 Jan 2017 18:23:23 +0100 Subject: [PATCH 003/327] Update README.md --- Simulated annealing/README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Simulated annealing/README.md b/Simulated annealing/README.md index e7fe75778..3a36464d7 100644 --- a/Simulated annealing/README.md +++ b/Simulated annealing/README.md @@ -17,10 +17,12 @@ Pseucocode Sbest = Scurrent temperature = temperature * (1-coolingRate) -Common acceptance criteria : P(accept) <- exp((e-ne)/T) where - e is the current energy ( current solution ), - ne is new energy ( new solution ), - T is current temperature. +Common acceptance criteria : + + P(accept) <- exp((e-ne)/T) where + e is the current energy ( current solution ), + ne is new energy ( new solution ), + T is current temperature. We use this algorithm to solve a Travelling salesman problem instance with 20 cities. The code is in `simann_example.swift` @@ -28,6 +30,7 @@ We use this algorithm to solve a Travelling salesman problem instance with 20 ci #See also [Simulated annealing on Wikipedia](https://en.wikipedia.org/wiki/Simulated_annealing) + [Travelling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) Written for Swift Algorithm Club by [Mike Taghavi](https://github.com/mitghi) From 3ef6ef4a520b62bea0aa713be96eba0eb1d490b2 Mon Sep 17 00:00:00 2001 From: Borja Arias Drake Date: Sun, 6 Aug 2017 20:14:49 +0100 Subject: [PATCH 004/327] Add conformance to Collection protocol for LinkedList class. --- .../LinkedList.playground/Contents.swift | 63 ++++++++++++++++++ Linked List/LinkedList.swift | 54 +++++++++++++++ Linked List/README.markdown | 66 +++++++++++++++++++ Linked List/Tests/LinkedListTests.swift | 8 +++ 4 files changed, 191 insertions(+) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index b78ee4809..ed3de41be 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -317,6 +317,61 @@ extension LinkedList: ExpressibleByArrayLiteral { } } +// MARK: - Collection +extension LinkedList : Collection { + + public typealias Index = LinkedListIndex + + /// The position of the first element in a nonempty collection. + /// + /// If the collection is empty, `startIndex` is equal to `endIndex`. + /// - Complexity: O(1) + public var startIndex: Index { + get { + return LinkedListIndex(node: head, tag: 0) + } + } + + /// The collection's "past the end" position---that is, the position one + /// greater than the last valid subscript argument. + /// - Complexity: O(n), where n is the number of elements in the list. This can be improved by keeping a reference + /// to the last node in the collection. + public var endIndex: Index { + get { + if let h = self.head { + return LinkedListIndex(node: h, tag: count) + } else { + return LinkedListIndex(node: nil, tag: startIndex.tag) + } + } + } + + public subscript(position: Index) -> T { + get { + return position.node!.value + } + } + + public func index(after idx: Index) -> Index { + return LinkedListIndex(node: idx.node?.next, tag: idx.tag+1) + } +} + +// MARK: - Collection Index +/// Custom index type that contains a reference to the node at index 'tag' +public struct LinkedListIndex : Comparable +{ + fileprivate let node: LinkedList.LinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } +} //: Ok, now that the declarations are done, let's see our Linked List in action: let list = LinkedList() list.isEmpty // true @@ -392,3 +447,11 @@ let listArrayLiteral2: LinkedList = ["Swift", "Algorithm", "Club"] listArrayLiteral2.count // 3 listArrayLiteral2[0] // "Swift" listArrayLiteral2.removeLast() // "Club" + + +// Conformance to the Collection protocol +let collection: LinkedList = [1, 2, 3, 4, 5] +let index2 = collection.index(collection.startIndex, offsetBy: 2) +let value = collection[index2] // 3 + + diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 94e978c07..f51064e01 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -244,3 +244,57 @@ extension LinkedList: ExpressibleByArrayLiteral { } } } + +extension LinkedList : Collection { + + public typealias Index = LinkedListIndex + + /// The position of the first element in a nonempty collection. + /// + /// If the collection is empty, `startIndex` is equal to `endIndex`. + /// - Complexity: O(1) + public var startIndex: Index { + get { + return LinkedListIndex(node: head, tag: 0) + } + } + + /// The collection's "past the end" position---that is, the position one + /// greater than the last valid subscript argument. + /// - Complexity: O(n), where n is the number of elements in the list. This can be improved by keeping a reference + /// to the last node in the collection. + public var endIndex: Index { + get { + if let h = self.head { + return LinkedListIndex(node: h, tag: count) + } else { + return LinkedListIndex(node: nil, tag: startIndex.tag) + } + } + } + + public subscript(position: Index) -> T { + get { + return position.node!.value + } + } + + public func index(after idx: Index) -> Index { + return LinkedListIndex(node: idx.node?.next, tag: idx.tag+1) + } +} + +/// Custom index type that contains a reference to the node at index 'tag' +public struct LinkedListIndex : Comparable +{ + fileprivate let node: LinkedList.LinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } +} diff --git a/Linked List/README.markdown b/Linked List/README.markdown index c03023c42..f1b1a2480 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -535,6 +535,72 @@ The big difference with the class-based version is that any modification you mak [I might fill out this section in more detail if there's a demand for it.] +## Conforming to the Collection protocol +Types that conform to the Sequence protocol, whose elements can be traversed multiple times, nondestructively, and accessed by indexed subscript should conform to the Collection protocol defined in Swift's Standard Library. + +Doing so grants access to a very large number of properties and operations that are common when dealing collections of data. In addition to this, it lets custom types follow the patterns that are common to Swift developers. + +In order to conform to this protocol, classes need to provide: + 1 `startIndex` and `endIndex` properties. + 2 Subscript access to elements as O(1). Diversions of this time complexity need to be documented. + +```swift +/// The position of the first element in a nonempty collection. +public var startIndex: Index { + get { + return LinkedListIndex(node: head, tag: 0) + } +} + +/// The collection's "past the end" position---that is, the position one +/// greater than the last valid subscript argument. +/// - Complexity: O(n), where n is the number of elements in the list. +/// This diverts from the protocol's expectation. +public var endIndex: Index { + get { + if let h = self.head { + return LinkedListIndex(node: h, tag: count) + } else { + return LinkedListIndex(node: nil, tag: startIndex.tag) + } + } +} +``` + +```swift +public subscript(position: Index) -> T { + get { + return position.node!.value + } +} +``` + +Becuase collections are responsible for managing their own indexes, the implementation below keeps a reference to a node in the list. A tag property in the index represents the position of the node in the list. + +```swift +/// Custom index type that contains a reference to the node at index 'tag' +public struct LinkedListIndex : Comparable +{ + fileprivate let node: LinkedList.LinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } +} +``` + +Finally, the linked is is able to calculate the index after a given one with the following implementation. +```swift +public func index(after idx: Index) -> Index { + return LinkedListIndex(node: idx.node?.next, tag: idx.tag+1) +} +``` + ## Some things to keep in mind Linked lists are flexible but many operations are **O(n)**. diff --git a/Linked List/Tests/LinkedListTests.swift b/Linked List/Tests/LinkedListTests.swift index 0b2b116df..bc9831a41 100755 --- a/Linked List/Tests/LinkedListTests.swift +++ b/Linked List/Tests/LinkedListTests.swift @@ -337,4 +337,12 @@ class LinkedListTest: XCTestCase { XCTAssertEqual(arrayLiteralInitExplicit.removeLast(), 3) XCTAssertEqual(arrayLiteralInitExplicit.count, 2) } + + func testConformanceToCollectionProtocol() { + let collection: LinkedList = [1, 2, 3, 4, 5] + let index2 = collection.index(collection.startIndex, offsetBy: 2) + let value = collection[index2] + + XCTAssertTrue(value == 3) + } } From f5678857ca24a9c1403a5f721d62e73ef90e64c3 Mon Sep 17 00:00:00 2001 From: Borja Arias Drake Date: Sun, 6 Aug 2017 20:23:17 +0100 Subject: [PATCH 005/327] Fix styling issue; Parentheses on new line. --- Linked List/LinkedList.playground/Contents.swift | 3 +-- Linked List/LinkedList.swift | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index ed3de41be..7805d4a37 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -359,8 +359,7 @@ extension LinkedList : Collection { // MARK: - Collection Index /// Custom index type that contains a reference to the node at index 'tag' -public struct LinkedListIndex : Comparable -{ +public struct LinkedListIndex : Comparable { fileprivate let node: LinkedList.LinkedListNode? fileprivate let tag: Int diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index f51064e01..e7e2c714e 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -285,8 +285,7 @@ extension LinkedList : Collection { } /// Custom index type that contains a reference to the node at index 'tag' -public struct LinkedListIndex : Comparable -{ +public struct LinkedListIndex : Comparable { fileprivate let node: LinkedList.LinkedListNode? fileprivate let tag: Int From 5570a711df3d1bc79ce921bd94fe2b9365e141ad Mon Sep 17 00:00:00 2001 From: Borja Arias Drake Date: Sun, 6 Aug 2017 20:32:55 +0100 Subject: [PATCH 006/327] Add two examples of Sequence methods gained through the conformance to Collection protocol. --- Linked List/LinkedList.playground/Contents.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 7805d4a37..ef70c561b 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -453,4 +453,16 @@ let collection: LinkedList = [1, 2, 3, 4, 5] let index2 = collection.index(collection.startIndex, offsetBy: 2) let value = collection[index2] // 3 +// Iterating in a for loop, since the Sequence protocol allows this. +var sum = 0 +for element in collection { + sum += element +} +// sum is 15 + +// Another way of achieving the same result though 'reduce', another method defined in an extension of Sequence. Collections are Sequences. +let result = collection.reduce(0) {$0 + $1} // 15 + + + From 71ab3f8eb62bea0886536f2fd12b7b703ea0cb2e Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Tue, 26 Sep 2017 15:34:03 -0700 Subject: [PATCH 007/327] algorithm proposal --- Genetic/README.markdown | 2 + Genetic/gen.swift | 179 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 Genetic/README.markdown create mode 100644 Genetic/gen.swift diff --git a/Genetic/README.markdown b/Genetic/README.markdown new file mode 100644 index 000000000..7cad649cb --- /dev/null +++ b/Genetic/README.markdown @@ -0,0 +1,2 @@ +# todo +refactoring https://gist.github.com/blainerothrock/efda6e12fe10792c99c990f8ff3daeba for swift 4. Creating a tutorial and writing in more playground friendly format diff --git a/Genetic/gen.swift b/Genetic/gen.swift new file mode 100644 index 000000000..72830b8a7 --- /dev/null +++ b/Genetic/gen.swift @@ -0,0 +1,179 @@ +/* + base .. to be refactored +*/ + +import Foundation + +// HELPERS +/* + String extension to convert a string to ascii value +*/ +extension String { + var asciiArray: [UInt8] { + return unicodeScalars.filter{$0.isASCII}.map{UInt8($0.value)} + } +} + +/* + helper function to return a random character string +*/ +func randomChar() -> UInt8 { + + let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray + let len = UInt32(letters.count-1) + + let rand = Int(arc4random_uniform(len)) + return letters[rand] +} + +// END HELPERS + +let OPTIMAL:[UInt8] = "Hello, World".asciiArray +let DNA_SIZE = OPTIMAL.count +let POP_SIZE = 50 +let GENERATIONS = 5000 +let MUTATION_CHANCE = 100 + +/* + calculated the fitness based on approximate string matching + compares each character ascii value difference and adds that to a total fitness + optimal string comparsion = 0 +*/ +func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { + + var fitness = 0 + for c in 0...dna.count-1 { + fitness += abs(Int(dna[c]) - Int(optimal[c])) + } + return fitness +} + +/* + randomly mutate the string +*/ +func mutate(dna:[UInt8], mutationChance:Int, dnaSize:Int) -> [UInt8] { + var outputDna = dna + + for i in 0.. (dna1:[UInt8], dna2:[UInt8]) { + let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) + + let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) + let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) + + return ( + [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), + [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) + ) +} + + +/* +returns a random population, used to start the evolution +*/ +func randomPopulation(populationSize: Int, dnaSize: Int) -> [[UInt8]] { + + let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray + let len = UInt32(letters.count) + + var pop = [[UInt8]]() + + for _ in 0.. (item:[UInt8], weight:Double) { + var weightTotal = 0.0 + for itemTuple in items { + weightTotal += itemTuple.weight; + } + + var n = Double(arc4random_uniform(UInt32(weightTotal * 1000000.0))) / 1000000.0 + + for itemTuple in items { + if n < itemTuple.weight { + return itemTuple + } + n = n - itemTuple.weight + } + return items[1] +} + +func main() { + + // generate the starting random population + var population:[[UInt8]] = randomPopulation(populationSize: POP_SIZE, dnaSize: DNA_SIZE) + // print("population: \(population), dnaSize: \(DNA_SIZE) ") + var fittest = [UInt8]() + + for generation in 0...GENERATIONS { + print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") + + var weightedPopulation = [(item:[UInt8], weight:Double)]() + + // calulcated the fitness of each individual in the population + // and add it to the weight population (weighted = 1.0/fitness) + for individual in population { + let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) + + let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) + + weightedPopulation.append(pair) + } + + population = [] + + // create a new generation using the individuals in the origional population + for _ in 0...POP_SIZE/2 { + let ind1 = weightedChoice(items: weightedPopulation) + let ind2 = weightedChoice(items: weightedPopulation) + + let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) + + // append to the population and mutate + population.append(mutate(dna: offspring.dna1, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) + population.append(mutate(dna: offspring.dna2, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) + } + + fittest = population[0] + var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) + + // parse the population for the fittest string + for indv in population { + let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) + if indvFitness < minFitness { + fittest = indv + minFitness = indvFitness + } + } + if minFitness == 0 { break; } + } + print("fittest string: \(String(bytes: fittest, encoding: .ascii)!)") +} + +main() From 4b73295140df7cb645431aeb01b867f944725ef8 Mon Sep 17 00:00:00 2001 From: Jaap Wijnen Date: Thu, 26 Oct 2017 02:21:17 +0200 Subject: [PATCH 008/327] initial points lines planes commit --- .../project.pbxproj | 296 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../Points Lines Planes/2D/Line2D.swift | 161 ++++++++++ .../Points Lines Planes/2D/Point2D.swift | 40 +++ .../Points Lines Planes/main.swift | 24 ++ Points Lines Planes/README.md | 34 ++ 6 files changed, 562 insertions(+) create mode 100644 Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj create mode 100644 Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Points Lines Planes/Points Lines Planes/2D/Line2D.swift create mode 100644 Points Lines Planes/Points Lines Planes/2D/Point2D.swift create mode 100644 Points Lines Planes/Points Lines Planes/main.swift create mode 100644 Points Lines Planes/README.md diff --git a/Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj b/Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj new file mode 100644 index 000000000..aeba4777b --- /dev/null +++ b/Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj @@ -0,0 +1,296 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 8EA8A3BB1F9F7B6300FD8BC0 /* Point2D.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EA8A3BA1F9F7B6300FD8BC0 /* Point2D.swift */; }; + 8EA8A3BD1F9F7B7100FD8BC0 /* Line2D.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EA8A3BC1F9F7B7100FD8BC0 /* Line2D.swift */; }; + 8EF612481F9E00E000267358 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EF612471F9E00E000267358 /* main.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8EF612421F9E00E000267358 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 8EA8A3BA1F9F7B6300FD8BC0 /* Point2D.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Point2D.swift; sourceTree = ""; }; + 8EA8A3BC1F9F7B7100FD8BC0 /* Line2D.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line2D.swift; sourceTree = ""; }; + 8EF612441F9E00E000267358 /* Points Lines Planes */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "Points Lines Planes"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8EF612471F9E00E000267358 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8EF612411F9E00E000267358 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8EA8A3C21F9F7C9000FD8BC0 /* 2D */ = { + isa = PBXGroup; + children = ( + 8EA8A3BA1F9F7B6300FD8BC0 /* Point2D.swift */, + 8EA8A3BC1F9F7B7100FD8BC0 /* Line2D.swift */, + ); + path = 2D; + sourceTree = ""; + }; + 8EF6123B1F9E00DF00267358 = { + isa = PBXGroup; + children = ( + 8EF612461F9E00E000267358 /* Points Lines Planes */, + 8EF612451F9E00E000267358 /* Products */, + ); + sourceTree = ""; + }; + 8EF612451F9E00E000267358 /* Products */ = { + isa = PBXGroup; + children = ( + 8EF612441F9E00E000267358 /* Points Lines Planes */, + ); + name = Products; + sourceTree = ""; + }; + 8EF612461F9E00E000267358 /* Points Lines Planes */ = { + isa = PBXGroup; + children = ( + 8EF612471F9E00E000267358 /* main.swift */, + 8EA8A3C21F9F7C9000FD8BC0 /* 2D */, + ); + path = "Points Lines Planes"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8EF612431F9E00E000267358 /* Points Lines Planes */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8EF6124B1F9E00E000267358 /* Build configuration list for PBXNativeTarget "Points Lines Planes" */; + buildPhases = ( + 8EF612401F9E00E000267358 /* Sources */, + 8EF612411F9E00E000267358 /* Frameworks */, + 8EF612421F9E00E000267358 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Points Lines Planes"; + productName = "Points Lines Planes"; + productReference = 8EF612441F9E00E000267358 /* Points Lines Planes */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8EF6123C1F9E00DF00267358 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0900; + LastUpgradeCheck = 0900; + ORGANIZATIONNAME = Workmoose; + TargetAttributes = { + 8EF612431F9E00E000267358 = { + CreatedOnToolsVersion = 9.0.1; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 8EF6123F1F9E00DF00267358 /* Build configuration list for PBXProject "Points Lines Planes" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 8EF6123B1F9E00DF00267358; + productRefGroup = 8EF612451F9E00E000267358 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8EF612431F9E00E000267358 /* Points Lines Planes */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8EF612401F9E00E000267358 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8EA8A3BB1F9F7B6300FD8BC0 /* Point2D.swift in Sources */, + 8EF612481F9E00E000267358 /* main.swift in Sources */, + 8EA8A3BD1F9F7B7100FD8BC0 /* Line2D.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 8EF612491F9E00E000267358 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 8EF6124A1F9E00E000267358 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + }; + name = Release; + }; + 8EF6124C1F9E00E000267358 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7C4LVS3ZVC; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 8EF6124D1F9E00E000267358 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7C4LVS3ZVC; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8EF6123F1F9E00DF00267358 /* Build configuration list for PBXProject "Points Lines Planes" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8EF612491F9E00E000267358 /* Debug */, + 8EF6124A1F9E00E000267358 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8EF6124B1F9E00E000267358 /* Build configuration list for PBXNativeTarget "Points Lines Planes" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8EF6124C1F9E00E000267358 /* Debug */, + 8EF6124D1F9E00E000267358 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8EF6123C1F9E00DF00267358 /* Project object */; +} diff --git a/Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..82bfe2b7d --- /dev/null +++ b/Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Points Lines Planes/Points Lines Planes/2D/Line2D.swift b/Points Lines Planes/Points Lines Planes/2D/Line2D.swift new file mode 100644 index 000000000..c92cbdbed --- /dev/null +++ b/Points Lines Planes/Points Lines Planes/2D/Line2D.swift @@ -0,0 +1,161 @@ +// +// Line2D.swift +// Points Lines Planes +// +// Created by Jaap Wijnen on 24-10-17. +// + +struct Line2D: Equatable { + + var slope: Slope + var offset: Double + var direction: Direction + + enum Slope: Equatable { + case finite(slope: Double) + case infinite(offset: Double) + + static func ==(lhs: Slope, rhs: Slope) -> Bool { + switch (lhs, rhs) { + case (.finite(let slope1), .finite(let slope2)): return slope1 == slope2 + case (.infinite(let offset1), .infinite(let offset2)): return offset1 == offset2 + default: return false + } + } + } + + enum Direction: Equatable { + case increasing + case decreasing + + static func ==(lhs: Direction, rhs: Direction) -> Bool { + switch (lhs, rhs) { + case (.increasing, .increasing): return true + case (.decreasing, .decreasing): return true + default: return false + } + } + } + + init(from p1: Point2D, to p2: Point2D) { + if p1 == p2 { fatalError("Points can not be equal when creating a line between them") } + if p1.x == p2.x { + self.slope = .infinite(offset: p1.x) + self.offset = 0 + self.direction = p1.y < p2.y ? .increasing : .decreasing + + return + } + + let slope = (p1.y - p2.y)/(p1.x - p2.x) + self.slope = .finite(slope: slope) + offset = (p1.y + p2.y - slope * (p1.x + p2.x))/2 + if slope >= 0 { + // so a horizontal line going left to right is called increasing + self.direction = p1.x < p2.x ? .increasing : .decreasing + } else { + self.direction = p1.x < p2.x ? .decreasing : .increasing + } + } + + fileprivate init(slope: Slope, offset: Double, direction: Direction) { + self.slope = slope + self.offset = offset + self.direction = direction + } + + // returns y coordinate on line for given x + func y(at x: Double) -> Double { + switch self.slope { + case .finite(let slope): + return slope * x + self.offset + case .infinite: + fatalError("y can be anywhere on vertical line") + } + } + + // returns x coordinate on line for given y + func x(at y: Double) -> Double { + switch self.slope { + case .finite(let slope): + if slope == 0 { + fatalError("x can be anywhere on horizontal line") + } + return (y - self.offset)/slope + case .infinite(let offset): + return offset + } + } + + // finds intersection point between two lines. returns nil when lines don't intersect or lie on top of each other. + func intersect(with line: Line2D) -> Point2D? { + if self == line { return nil } + switch (self.slope, line.slope) { + case (.infinite, .infinite): + // lines are either parallel or on top of each other. + return nil + case (.finite(let slope1), .finite(let slope2)): + if slope1 == slope2 { return nil } // lines are parallel + // lines are not parallel calculate intersection point + let x = (line.offset - self.offset)/(slope1 - slope2) + let y = (slope1 + slope2) * x + self.offset + line.offset + return Point2D(x: x, y: y) + case (.infinite(let offset), .finite): + // one line is vertical so we only check what y value the other line has at that point + let x = offset + let y = line.y(at: x) + return Point2D(x: x, y: y) + case (.finite, .infinite(let offset)): + // one line is vertical so we only check what y value the other line has at that point + // lines are switched with respect to case above this one + let x = offset + let y = self.y(at: x) + return Point2D(x: x, y: y) + } + } + + // returns a line perpendicular to self at the given y coordinate + // direction of perpendicular lines always changes clockwise + func perpendicularLineAt(y: Double) -> Line2D { + return perpendicularLineAt(p: Point2D(x: self.x(at: y), y: y)) + } + + // returns a line perpendicular to self at the given x coordinate + // direction of perpendicular lines always changes clockwise + func perpendicularLineAt(x: Double) -> Line2D { + return perpendicularLineAt(p: Point2D(x: x, y: self.y(at: x))) + } + + private func perpendicularLineAt(p: Point2D) -> Line2D { + switch self.slope { + case .finite(let slope): + if slope == 0 { + // line is horizontal so new line will be vertical + let dir: Direction = self.direction == .increasing ? .decreasing : .increasing + return Line2D(slope: .infinite(offset: p.x), offset: 0, direction: dir) + } + + // line is neither horizontal nor vertical + // we make a new line through the point p with new slope -1/slope + let offset = (slope + 1/slope)*p.x + self.offset + + // determine direction of new line based on direction of the old line and its slope + let dir: Direction + switch self.direction { + case .increasing: + dir = slope > 0 ? .decreasing : .increasing + case .decreasing: + dir = slope > 0 ? .increasing : .decreasing + } + return Line2D(slope: .finite(slope: -1/slope), offset: offset, direction: dir) + case .infinite: + // line is vertical so new line will be horizontal + let dir: Direction = self.direction == .increasing ? .increasing : .decreasing + return Line2D(slope: .finite(slope: 0), offset: p.y, direction: dir) + } + } + + static func ==(lhs: Line2D, rhs: Line2D) -> Bool { + return lhs.slope == rhs.slope && lhs.offset == rhs.offset && lhs.direction == rhs.direction + } +} diff --git a/Points Lines Planes/Points Lines Planes/2D/Point2D.swift b/Points Lines Planes/Points Lines Planes/2D/Point2D.swift new file mode 100644 index 000000000..f51ffd64d --- /dev/null +++ b/Points Lines Planes/Points Lines Planes/2D/Point2D.swift @@ -0,0 +1,40 @@ +// +// Point2D.swift +// Points Lines Planes +// +// Created by Jaap Wijnen on 24-10-17. +// + +struct Point2D: Equatable { + var x: Double + var y: Double + + static func ==(lhs: Point2D, rhs: Point2D) -> Bool { + return lhs.x == rhs.x && lhs.y == rhs.y + } + + // returns true if point is on or right of line + func isRight(of line: Line2D) -> Bool { + switch line.slope { + case .finite: + let y = line.y(at: self.x) + switch line.direction { + case .increasing: + return y >= self.y + case .decreasing: + return y <= self.y + } + case .infinite(let offset): + switch line.direction { + case .increasing: + return self.x >= offset + case .decreasing: + return self.x <= offset + } + } + } + + func isLeft(of line: Line2D) -> Bool { + return !self.isRight(of: line) + } +} diff --git a/Points Lines Planes/Points Lines Planes/main.swift b/Points Lines Planes/Points Lines Planes/main.swift new file mode 100644 index 000000000..02137fc9d --- /dev/null +++ b/Points Lines Planes/Points Lines Planes/main.swift @@ -0,0 +1,24 @@ +// +// main.swift +// Points Lines Planes +// +// Created by Jaap Wijnen on 23-10-17. +// + +let p0 = Point2D(x: 0, y: 2) +let p1 = Point2D(x: 1, y: 1) +let p2 = Point2D(x: 1, y: 3) +let p3 = Point2D(x: 3, y: 1) +let p4 = Point2D(x: 3, y: 3) + +let horLine = Line2D(from: p1, to: p3) +let verLine = Line2D(from: p1, to: p2) +let line45 = Line2D(from: p1, to: p4) + +print(horLine.intersect(with: verLine)) +print(p0.isRight(of: line45)) +print(p0.isRight(of: horLine)) +print(p0.isRight(of: verLine)) +let lineperp = horLine.perpendicularLineAt(x: 2) +print(lineperp) + diff --git a/Points Lines Planes/README.md b/Points Lines Planes/README.md new file mode 100644 index 000000000..23c965978 --- /dev/null +++ b/Points Lines Planes/README.md @@ -0,0 +1,34 @@ +# Points Lines (Planes) +This implements data structures for points lines and planes(not yet) in (for now) 2D space and a few functions to play around with them. This was originally written to improve on the Convex Hull algorithm but I thought it might be a nice addition in itself. Im planning to add 3D implementations as well. + +# implementation +Two `struct`s are implemented the `Point2D` and `Line2D`. + +``` +struct Point2D: { + var x: Double + var y: double +} +``` + +``` +struct Line2D { + var slope: Slope + var offset: Double + var direction: Direction +} +``` +Here `Slope` is an enum to account for vertical lines. +slope is infinite for vertical lines, offset is the x coordinate where the line crosses the line `y=0`. +slope is finite for any other line and contains a double with the actual value of the slope. +``` +enum Slope { + case finite(slope: Double) + case infinite(offset: Double) +} +``` +`Line2D` also contains a `Direction` enum. This is introduced in order to make lines directional in order to be able to determine what is left and right of a certain line. It is `.increasing` if the line points in positive y direction and `.decreasing` if it points in the negative y direction. + +`Line2D`'s offset is the the y-coordinate where the line crosses the vertical x=0 line + +*Written for the Swift Algorithm Club by Jaap Wijnen.* From 7f6f5a5a56baa1a1bb6854dd2a29699f1be2c558 Mon Sep 17 00:00:00 2001 From: Jaap Wijnen Date: Thu, 26 Oct 2017 02:40:29 +0200 Subject: [PATCH 009/327] typo --- Points Lines Planes/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Points Lines Planes/README.md b/Points Lines Planes/README.md index 23c965978..2d36667ec 100644 --- a/Points Lines Planes/README.md +++ b/Points Lines Planes/README.md @@ -29,6 +29,6 @@ enum Slope { ``` `Line2D` also contains a `Direction` enum. This is introduced in order to make lines directional in order to be able to determine what is left and right of a certain line. It is `.increasing` if the line points in positive y direction and `.decreasing` if it points in the negative y direction. -`Line2D`'s offset is the the y-coordinate where the line crosses the vertical x=0 line +`Line2D`'s offset is the the y-coordinate where the line crosses the vertical `x=0` line. *Written for the Swift Algorithm Club by Jaap Wijnen.* From 6ca1ad1da1e6c629e164a23c6b5759225f61962e Mon Sep 17 00:00:00 2001 From: Hai Nguyen Date: Sat, 21 Oct 2017 10:02:08 -0700 Subject: [PATCH 010/327] Add .gfm-render.sh --- .travis.yml | 82 +++++++++++++++++++------------------- gfm-render.sh | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 39 deletions(-) create mode 100755 gfm-render.sh diff --git a/.travis.yml b/.travis.yml index 5d2a05848..7cd02c9bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,46 +4,50 @@ osx_image: xcode9 install: +- gem install xcpretty-travis-formatter # - ./install_swiftlint.sh script: -- xcodebuild test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests -- xcodebuild test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Binary\ Search/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Boyer-Moore-Horspool/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Binary\ Search\ Tree/Solution\ 1/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Bloom\ Filter/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Bounded\ Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Breadth-First\ Search/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Bucket\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./B-Tree/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Comb\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Convex\ Hull/Convex\ Hull.xcodeproj -scheme Tests -destination 'platform=iOS Simulator,name=iPhone 7,OS=11.0' -- xcodebuild test -project ./Counting\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Depth-First\ Search/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Graph/Graph.xcodeproj -scheme GraphTests -- xcodebuild test -project ./Heap/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Heap\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Insertion\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./K-Means/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Linked\ List/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Singly\ Linked\ List/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Longest\ Common\ Subsequence/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Minimum\ Spanning\ Tree\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Queue/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Quicksort/Tests/Tests-Quicksort.xcodeproj -scheme Tests-Quicksort -- xcodebuild test -project ./Radix\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Rootish\ Array\ Stack/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Select\ Minimum\ Maximum/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Selection\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Shell\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Shortest\ Path\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Single-Source\ Shortest\ Paths\ \(Weighted\)/SSSP.xcodeproj -scheme SSSPTests -- xcodebuild test -project ./Stack/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests -- xcodebuild test -project ./Treap/Treap/Treap.xcodeproj -scheme Tests -- xcodebuild test -project ./Palindromes/Test/Test.xcodeproj -scheme Test -- xcodebuild test -project ./Ternary\ Search\ Tree/Tests/Tests.xcodeproj -scheme Tests +- xcodebuild test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Binary\ Search/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Boyer-Moore-Horspool/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Binary\ Search\ Tree/Solution\ 1/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Bloom\ Filter/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Bounded\ Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Breadth-First\ Search/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Bucket\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./B-Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Comb\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Convex\ Hull/Convex\ Hull.xcodeproj -scheme Tests -destination 'platform=iOS Simulator,name=iPhone 7,OS=11.0' | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Counting\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Depth-First\ Search/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Graph/Graph.xcodeproj -scheme GraphTests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Heap/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Heap\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Insertion\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./K-Means/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Linked\ List/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Singly\ Linked\ List/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Longest\ Common\ Subsequence/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Minimum\ Spanning\ Tree\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Queue/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Quicksort/Tests/Tests-Quicksort.xcodeproj -scheme Test-Quicksort | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Radix\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Rootish\ Array\ Stack/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Select\ Minimum\ Maximum/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Selection\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Shell\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Shortest\ Path\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Single-Source\ Shortest\ Paths\ \(Weighted\)/SSSP.xcodeproj -scheme SSSPTests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Stack/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Treap/Treap/Treap.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Palindromes/Test/Test.xcodeproj -scheme Test | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Ternary\ Search\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` + +after_success: +- if [[ "$TRAVIS_BRANCH" == "master" ]]; then ./gfm-render.sh; fi diff --git a/gfm-render.sh b/gfm-render.sh new file mode 100755 index 000000000..09c026d55 --- /dev/null +++ b/gfm-render.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash + +# $1 - readme +function render_markdown_to_html { + # escape escaping characters + if [[ $(uname) == "Darwin" ]]; then + content=$( + cat "$1" \ + | sed 's/\\/\\\\/g' \ + | sed 's/"/\\"/g' \ + | sed $'s/\t/\\\\t/g' \ + | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\\n/g' \ + ) + else + content=$( + cat "$1" \ + | sed 's/\\/\\\\/g' \ + | sed 's/"/\\"/g' \ + | sed 's/\t/\\t/g' \ + | sed ':a;N;$!ba;s/\n/\\n/g' \ + ) + fi + + # network call to GitHub API + json="{\"text\":\"$content\",\"mode\":\"gfm\",\"context\":\"$USERNAME/swift-algorithm-club\"}" + echo -e "$(curl -s --data "$json" -u $USERNAME:$TOKEN https://api.github.com/markdown)" +} + +# $1 - comment +function push_to_gh_pages { + git checkout -b gh-pages + git add . + git commit -m "$1" + git push -f https://$TOKEN@github.com/$USERNAME/swift-algorithm-club.git gh-pages +} + +# download github systax highlight stylesheet +echo "> Downloading github-light.css..." +curl -s -O https://raw.githubusercontent.com/primer/github-syntax-light/master/lib/github-light.css + +# if index.html does not exist, create one; +# otherwise, empty its content. +if [[ -z index.html ]]; then + touch index.html +else + > index.html +fi + +# iterate immediate directories +find . -maxdepth 1 -type d | while read folder; do + readme='' + + # get the right extension for the README file if there is one + if [[ -f $folder/README.md ]]; then readme="$folder/README.md"; fi + if [[ -f $folder/README.markdown ]]; then readme="$folder/README.markdown"; fi + + # exclude the repository's README + if [[ !(-z $readme) && ($readme != "./README.markdown") ]]; then + name=$(basename "$folder") + echo "> Generating $name/index.html..." + + cat > "$folder/index.html" << EOF + + + + + + + $(render_markdown_to_html "$readme") + + +EOF + # temporarily write the list of HTML filenames to the main index.html + echo "$lists
  • $name
  • " >> index.html + fi +done + +echo "

    Swift Algorithm

      $(echo -n $(cat index.html))
    " > index.html + +# push to gh-pages +if [[ $CI = true ]]; then push_to_gh_pages "Generated by TravisCI on $(date +%D)"; fi From a642a929ae4ce72ba0f00fc037c292a02db0fc9a Mon Sep 17 00:00:00 2001 From: vincentngo Date: Thu, 16 Nov 2017 22:37:27 -0500 Subject: [PATCH 011/327] Add username as test --- gfm-render.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gfm-render.sh b/gfm-render.sh index 09c026d55..88970dd15 100755 --- a/gfm-render.sh +++ b/gfm-render.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +USERNAME="raywenderlich" + # $1 - readme function render_markdown_to_html { # escape escaping characters From 7cb8185679cdc3acf38e9123ef7503fba5b4d116 Mon Sep 17 00:00:00 2001 From: Alejandro Isaza Date: Sat, 7 Oct 2017 15:50:19 -0700 Subject: [PATCH 012/327] Add A* algorithm --- A-Star/AStar.swift | 153 +++++++++ A-Star/README.md | 7 + A-Star/Tests/AStarTests.swift | 57 ++++ .../AStarTests.xcodeproj/project.pbxproj | 291 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + A-Star/Tests/Info.plist | 24 ++ Hashed Heap/HashedHeap.swift | 13 +- .../contents.xcworkspacedata | 23 ++ 8 files changed, 574 insertions(+), 1 deletion(-) create mode 100644 A-Star/AStar.swift create mode 100644 A-Star/README.md create mode 100755 A-Star/Tests/AStarTests.swift create mode 100644 A-Star/Tests/AStarTests.xcodeproj/project.pbxproj create mode 100644 A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 A-Star/Tests/Info.plist diff --git a/A-Star/AStar.swift b/A-Star/AStar.swift new file mode 100644 index 000000000..41a9fac6c --- /dev/null +++ b/A-Star/AStar.swift @@ -0,0 +1,153 @@ +// Written by Alejandro Isaza. + +import Foundation + +public protocol Graph { + associatedtype Vertex: Hashable + associatedtype Edge: WeightedEdge where Edge.Vertex == Vertex + + /// Lists all edges going out from a vertex. + func edgesOutgoing(from vertex: Vertex) -> [Edge] +} + +public protocol WeightedEdge { + associatedtype Vertex + + /// The edge's cost. + var cost: Double { get } + + /// The target vertex. + var target: Vertex { get } +} + +public final class AStar { + /// The graph to search on. + public let graph: G + + /// The heuristic cost function that estimates the cost between two vertices. + /// + /// - Note: The heuristic function needs to always return a value that is lower-than or equal to the actual + /// cost for the resulting path of the A* search to be optimal. + public let heuristic: (G.Vertex, G.Vertex) -> Double + + /// Open list of nodes to expand. + private var open: HashedHeap> + + /// Closed list of vertices already expanded. + private var closed = Set() + + /// Actual vertex cost for vertices we already encountered (refered to as `g` on the literature). + private var costs = Dictionary() + + /// Store the previous node for each expanded node to recreate the path. + private var parents = Dictionary() + + /// Initializes `AStar` with a graph and a heuristic cost function. + public init(graph: G, heuristic: @escaping (G.Vertex, G.Vertex) -> Double) { + self.graph = graph + self.heuristic = heuristic + open = HashedHeap(sort: <) + } + + /// Finds an optimal path between `source` and `target`. + /// + /// - Precondition: both `source` and `target` belong to `graph`. + public func path(start: G.Vertex, target: G.Vertex) -> [G.Vertex] { + open.insert(Node(vertex: start, cost: 0, estimate: heuristic(start, target))) + while !open.isEmpty { + guard let node = open.remove() else { + break + } + costs[node.vertex] = node.cost + + if (node.vertex == target) { + let path = buildPath(start: start, target: target) + cleanup() + return path + } + + if !closed.contains(node.vertex) { + expand(node: node, target: target) + closed.insert(node.vertex) + } + } + + // No path found + return [] + } + + private func expand(node: Node, target: G.Vertex) { + let edges = graph.edgesOutgoing(from: node.vertex) + for edge in edges { + let g = cost(node.vertex) + edge.cost + if g < cost(edge.target) { + open.insert(Node(vertex: edge.target, cost: g, estimate: heuristic(edge.target, target))) + parents[edge.target] = node.vertex + } + } + } + + private func cost(_ vertex: G.Edge.Vertex) -> Double { + if let c = costs[vertex] { + return c + } + + let node = Node(vertex: vertex, cost: Double.greatestFiniteMagnitude, estimate: 0) + if let index = open.index(of: node) { + return open[index].cost + } + + return Double.greatestFiniteMagnitude + } + + private func buildPath(start: G.Vertex, target: G.Vertex) -> [G.Vertex] { + var path = Array() + path.append(target) + + var current = target + while current != start { + guard let parent = parents[current] else { + return [] // no path found + } + current = parent + path.append(current) + } + + return path.reversed() + } + + private func cleanup() { + open.removeAll() + closed.removeAll() + parents.removeAll() + } +} + +private struct Node: Hashable, Comparable { + /// The graph vertex. + var vertex: V + + /// The actual cost between the start vertex and this vertex. + var cost: Double + + /// Estimated (heuristic) cost betweent this vertex and the target vertex. + var estimate: Double + + public init(vertex: V, cost: Double, estimate: Double) { + self.vertex = vertex + self.cost = cost + self.estimate = estimate + } + + static func < (lhs: Node, rhs: Node) -> Bool { + return lhs.cost + lhs.estimate < rhs.cost + rhs.estimate + } + + static func == (lhs: Node, rhs: Node) -> Bool { + return lhs.vertex == rhs.vertex + } + + var hashValue: Int { + return vertex.hashValue + } +} diff --git a/A-Star/README.md b/A-Star/README.md new file mode 100644 index 000000000..cafd5027a --- /dev/null +++ b/A-Star/README.md @@ -0,0 +1,7 @@ +# A* + +A* (pronounced "ay star") is a heuristic best-first search algorithm. A* minimizes node expansions, therefore minimizing the search time, by using a heuristic function. The heuristic function gives an estimate of the distance between two vertices. For instance if you are searching for a path between two points in a city, you can estimate the actual street distance with the straight-line distance. + +A* works by expanding the most promising nodes first, according to the heuristic function. In the city example it would choose streets which go in the general direction of the target first and, only if those are dead ends, backtrack and try other streets. This speeds up search in most sitations. + +A* is optimal (it always find the shortest path) if the heuristic function is admissible. A heuristic function is admissible if it never overestimates the cost of reaching the goal. In the extreme case of the heuristic function always retuning `0` A* acts exactly the same as [Dijkstra's Algorithm](../Dijkstra). The closer the heuristic function is the the actual distance the faster the search. diff --git a/A-Star/Tests/AStarTests.swift b/A-Star/Tests/AStarTests.swift new file mode 100755 index 000000000..87f674cd5 --- /dev/null +++ b/A-Star/Tests/AStarTests.swift @@ -0,0 +1,57 @@ +import Foundation +import XCTest + +struct GridGraph: Graph { + struct Vertex: Hashable { + var x: Int + var y: Int + + static func == (lhs: Vertex, rhs: Vertex) -> Bool { + return lhs.x == rhs.x && lhs.y == rhs.y + } + + public var hashValue: Int { + return x.hashValue ^ y.hashValue + } + } + + struct Edge: WeightedEdge { + var cost: Double + var target: Vertex + } + + func edgesOutgoing(from vertex: Vertex) -> [Edge] { + return [ + Edge(cost: 1, target: Vertex(x: vertex.x - 1, y: vertex.y)), + Edge(cost: 1, target: Vertex(x: vertex.x + 1, y: vertex.y)), + Edge(cost: 1, target: Vertex(x: vertex.x, y: vertex.y - 1)), + Edge(cost: 1, target: Vertex(x: vertex.x, y: vertex.y + 1)), + ] + } +} + +class AStarTests: XCTestCase { + func testSameStartAndEnd() { + let graph = GridGraph() + let astar = AStar(graph: graph, heuristic: manhattanDistance) + let path = astar.path(start: GridGraph.Vertex(x: 0, y: 0), target: GridGraph.Vertex(x: 0, y: 0)) + XCTAssertEqual(path.count, 1) + XCTAssertEqual(path[0].x, 0) + XCTAssertEqual(path[0].y, 0) + } + + func testDiagonal() { + let graph = GridGraph() + let astar = AStar(graph: graph, heuristic: manhattanDistance) + let path = astar.path(start: GridGraph.Vertex(x: 0, y: 0), target: GridGraph.Vertex(x: 10, y: 10)) + XCTAssertEqual(path.count, 21) + XCTAssertEqual(path[0].x, 0) + XCTAssertEqual(path[0].y, 0) + XCTAssertEqual(path[20].x, 10) + XCTAssertEqual(path[20].y, 10) + } + + func manhattanDistance(_ s: GridGraph.Vertex, _ t: GridGraph.Vertex) -> Double { + return Double(abs(s.x - t.x) + abs(s.y - t.y)) + } +} diff --git a/A-Star/Tests/AStarTests.xcodeproj/project.pbxproj b/A-Star/Tests/AStarTests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..cacd1e5ae --- /dev/null +++ b/A-Star/Tests/AStarTests.xcodeproj/project.pbxproj @@ -0,0 +1,291 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 611D099C1F8978AB00C7092B /* AStarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611D099B1F8978AB00C7092B /* AStarTests.swift */; }; + 611D099E1F8978BC00C7092B /* AStar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611D099D1F8978BB00C7092B /* AStar.swift */; }; + 611D09A01F89795100C7092B /* HashedHeap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611D099F1F89795100C7092B /* HashedHeap.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 611D099B1F8978AB00C7092B /* AStarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AStarTests.swift; sourceTree = ""; }; + 611D099D1F8978BB00C7092B /* AStar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AStar.swift; path = ../AStar.swift; sourceTree = ""; }; + 611D099F1F89795100C7092B /* HashedHeap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HashedHeap.swift; path = "../../Hashed Heap/HashedHeap.swift"; sourceTree = ""; }; + 7B2BBC801C779D720067B71D /* AStarTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AStarTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7B2BBC7D1C779D720067B71D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 7B2BBC681C779D710067B71D = { + isa = PBXGroup; + children = ( + 7B2BBC831C779D720067B71D /* Tests */, + 7B2BBC721C779D710067B71D /* Products */, + ); + sourceTree = ""; + }; + 7B2BBC721C779D710067B71D /* Products */ = { + isa = PBXGroup; + children = ( + 7B2BBC801C779D720067B71D /* AStarTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 7B2BBC831C779D720067B71D /* Tests */ = { + isa = PBXGroup; + children = ( + 611D099F1F89795100C7092B /* HashedHeap.swift */, + 611D099D1F8978BB00C7092B /* AStar.swift */, + 611D099B1F8978AB00C7092B /* AStarTests.swift */, + 7B2BBC941C779E7B0067B71D /* Info.plist */, + ); + name = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 7B2BBC7F1C779D720067B71D /* AStarTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "AStarTests" */; + buildPhases = ( + 7B2BBC7C1C779D720067B71D /* Sources */, + 7B2BBC7D1C779D720067B71D /* Frameworks */, + 7B2BBC7E1C779D720067B71D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AStarTests; + productName = TestsTests; + productReference = 7B2BBC801C779D720067B71D /* AStarTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 7B2BBC691C779D710067B71D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0900; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0900; + }; + }; + }; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "AStarTests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 7B2BBC681C779D710067B71D; + productRefGroup = 7B2BBC721C779D710067B71D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7B2BBC7F1C779D720067B71D /* AStarTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 7B2BBC7E1C779D720067B71D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7B2BBC7C1C779D720067B71D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 611D099C1F8978AB00C7092B /* AStarTests.swift in Sources */, + 611D099E1F8978BC00C7092B /* AStar.swift in Sources */, + 611D09A01F89795100C7092B /* HashedHeap.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + }; + name = Debug; + }; + 7B2BBC881C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + }; + name = Release; + }; + 7B2BBC8D1C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 7B2BBC8E1C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "AStarTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC871C779D720067B71D /* Debug */, + 7B2BBC881C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "AStarTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC8D1C779D720067B71D /* Debug */, + 7B2BBC8E1C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 7B2BBC691C779D710067B71D /* Project object */; +} diff --git a/A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/A-Star/Tests/Info.plist b/A-Star/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/A-Star/Tests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Hashed Heap/HashedHeap.swift b/Hashed Heap/HashedHeap.swift index be7d9ab78..106cdacb0 100644 --- a/Hashed Heap/HashedHeap.swift +++ b/Hashed Heap/HashedHeap.swift @@ -57,7 +57,12 @@ public struct HashedHeap { public var count: Int { return elements.count } - + + /// Accesses an element by its index. + public subscript(index: Int) -> T { + return elements[index] + } + /// Returns the index of the given element. /// /// This is the operation that a hashed heap optimizes in compassion with a normal heap. In a normal heap this @@ -141,6 +146,12 @@ public struct HashedHeap { } return removeLast() } + + /// Removes all elements from the heap. + public mutating func removeAll() { + elements.removeAll() + indices.removeAll() + } /// Removes the last element from the heap. /// diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 4cab8e2d4..28fb4f1a7 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -38,6 +38,29 @@ + + + + + + + + + + + + + + From cb26964f1ea032be9fbe7b64f1f6e849d1fda5d5 Mon Sep 17 00:00:00 2001 From: Alejandro Isaza Date: Sat, 7 Oct 2017 15:53:59 -0700 Subject: [PATCH 013/327] Add to .travis.yml --- .travis.yml | 1 + .../xcschemes/AStarTests.xcscheme | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme diff --git a/.travis.yml b/.travis.yml index 7cd02c9bc..30b54f140 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ install: script: +- xcodebuild test -project ./A-Star/Tests/AStarTests.xcodeproj -scheme AStarTests | xcpretty -f `xcpretty-travis-formatter` - xcodebuild test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` - xcodebuild test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests | xcpretty -f `xcpretty-travis-formatter` - xcodebuild test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` diff --git a/A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme b/A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme new file mode 100644 index 000000000..5473b4c0c --- /dev/null +++ b/A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2c2ec49e225861e9aa0da42b54e35c90f81ddbed Mon Sep 17 00:00:00 2001 From: Alejandro Isaza Date: Thu, 16 Nov 2017 22:17:19 -0800 Subject: [PATCH 014/327] Add example to README --- A-Star/Images/graph.dot | 12 ++++++++++++ A-Star/Images/graph.png | Bin 0 -> 20882 bytes A-Star/Images/step1.dot | 12 ++++++++++++ A-Star/Images/step1.png | Bin 0 -> 28753 bytes A-Star/Images/step2.dot | 12 ++++++++++++ A-Star/Images/step2.png | Bin 0 -> 29088 bytes A-Star/Images/step3.dot | 12 ++++++++++++ A-Star/Images/step3.png | Bin 0 -> 30158 bytes A-Star/Images/step4.dot | 12 ++++++++++++ A-Star/Images/step4.png | Bin 0 -> 30130 bytes A-Star/Images/step5.dot | 12 ++++++++++++ A-Star/Images/step5.png | Bin 0 -> 29802 bytes A-Star/Images/step6.dot | 12 ++++++++++++ A-Star/Images/step6.png | Bin 0 -> 29596 bytes A-Star/Images/step7.dot | 12 ++++++++++++ A-Star/Images/step7.png | Bin 0 -> 30012 bytes A-Star/README.md | 38 +++++++++++++++++++++++++++++++++++++- 17 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 A-Star/Images/graph.dot create mode 100644 A-Star/Images/graph.png create mode 100644 A-Star/Images/step1.dot create mode 100644 A-Star/Images/step1.png create mode 100644 A-Star/Images/step2.dot create mode 100644 A-Star/Images/step2.png create mode 100644 A-Star/Images/step3.dot create mode 100644 A-Star/Images/step3.png create mode 100644 A-Star/Images/step4.dot create mode 100644 A-Star/Images/step4.png create mode 100644 A-Star/Images/step5.dot create mode 100644 A-Star/Images/step5.png create mode 100644 A-Star/Images/step6.dot create mode 100644 A-Star/Images/step6.png create mode 100644 A-Star/Images/step7.dot create mode 100644 A-Star/Images/step7.png diff --git a/A-Star/Images/graph.dot b/A-Star/Images/graph.dot new file mode 100644 index 000000000..941d66232 --- /dev/null +++ b/A-Star/Images/graph.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "h = 3" ] } + { rank = same; B [ label = "h = 2" ]; C [ label = "h = 2" ]; D [ label = "h = 2" ] } + { rank = same; E [ label = "h = 1" ]; F [ label = "h = 1" ]; G [ label = "h = 1" ] } + { H [ label = "h = 0", style = filled, color = green ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/graph.png b/A-Star/Images/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..c0a4b1cc8fd31a372f6843f858703950a0adee4a GIT binary patch literal 20882 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 literal 0 HcmV?d00001 diff --git a/A-Star/Images/step1.dot b/A-Star/Images/step1.dot new file mode 100644 index 000000000..5785aea4c --- /dev/null +++ b/A-Star/Images/step1.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = deepskyblue1 ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightgrey ]; C [ label = "g = 1\nh = 2", style = filled, color = lightgrey ]; D [ label = "g = 1\nh = 2", style = filled, color = lightgrey ] } + { rank = same; E [ label = "g = \?\nh = 1" ]; F [ label = "g = \?\nh = 1" ]; G [ label = "g = \?\nh = 1" ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step1.png b/A-Star/Images/step1.png new file mode 100644 index 0000000000000000000000000000000000000000..a983033a2046b0e1dfc674249f28f08956c3edee GIT binary patch literal 28753 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 LEu|U-i{SqS++pzp literal 0 HcmV?d00001 diff --git a/A-Star/Images/step2.dot b/A-Star/Images/step2.dot new file mode 100644 index 000000000..0c8a9d53d --- /dev/null +++ b/A-Star/Images/step2.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = deepskyblue1 ]; C [ label = "g = 1\nh = 2", style = filled, color = lightgrey ]; D [ label = "g = 1\nh = 2", style = filled, color = lightgrey ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightgrey ]; F [ label = "g = \?\nh = 1" ]; G [ label = "g = \?\nh = 1" ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step2.png b/A-Star/Images/step2.png new file mode 100644 index 0000000000000000000000000000000000000000..10b4300f406be65ffb0e356666ed5ce965b5ca32 GIT binary patch literal 29088 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 EA5Jd { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step3.png b/A-Star/Images/step3.png new file mode 100644 index 0000000000000000000000000000000000000000..e195e7e8e11651f774405e1ca5be8bff514399dc GIT binary patch literal 30158 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 Of~umXLX{jW`2PX5&nCS9 literal 0 HcmV?d00001 diff --git a/A-Star/Images/step4.dot b/A-Star/Images/step4.dot new file mode 100644 index 000000000..16db76796 --- /dev/null +++ b/A-Star/Images/step4.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = deepskyblue1 ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightgrey ]; F [ label = "g = \?\nh = 1" ]; G [ label = "g = 2\nh = 1", style = filled, color = lightgrey ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step4.png b/A-Star/Images/step4.png new file mode 100644 index 0000000000000000000000000000000000000000..c07f34c80d2d69d1960b66b547c16134541b34ef GIT binary patch literal 30130 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 literal 0 HcmV?d00001 diff --git a/A-Star/Images/step5.dot b/A-Star/Images/step5.dot new file mode 100644 index 000000000..2986b6a90 --- /dev/null +++ b/A-Star/Images/step5.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = lightblue ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = deepskyblue1 ]; F [ label = "g = 3\nh = 1", style = filled, color = lightgrey ]; G [ label = "g = 2\nh = 1", style = filled, color = lightgrey ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step5.png b/A-Star/Images/step5.png new file mode 100644 index 0000000000000000000000000000000000000000..40a7008da206816baa056fa95d9f69c5b6db89ad GIT binary patch literal 29802 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 Y>gT576&OA6;h``x5{lwgqQ=4h3tFTHY5)KL literal 0 HcmV?d00001 diff --git a/A-Star/Images/step6.dot b/A-Star/Images/step6.dot new file mode 100644 index 000000000..b5e3179b6 --- /dev/null +++ b/A-Star/Images/step6.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = lightblue ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightblue ]; F [ label = "g = 3\nh = 1", style = filled, color = lightgrey ]; G [ label = "g = 2\nh = 1", style = filled, color = deepskyblue1 ] } + { H [ label = "g = 3\nh = 0", style = filled, color = lightgrey ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step6.png b/A-Star/Images/step6.png new file mode 100644 index 0000000000000000000000000000000000000000..9e7baef2622aaea8538f6f4fcfce9fc732f5403d GIT binary patch literal 29596 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 z

    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 literal 0 HcmV?d00001 diff --git a/A-Star/Images/step7.dot b/A-Star/Images/step7.dot new file mode 100644 index 000000000..c5b26b6b3 --- /dev/null +++ b/A-Star/Images/step7.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = lightblue ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightblue ]; F [ label = "g = 3\nh = 1", style = filled, color = lightgrey ]; G [ label = "g = 2\nh = 1", style = filled, color = lightblue ] } + { H [ label = "g = 3\nh = 0", style = filled, color = deepskyblue1 ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step7.png b/A-Star/Images/step7.png new file mode 100644 index 0000000000000000000000000000000000000000..0eedd638f24c57f671dc6905bc7910369436fbe5 GIT binary patch literal 30012 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 Date: Fri, 17 Nov 2017 16:51:17 -0500 Subject: [PATCH 015/327] Add Token for gfm render --- gfm-render.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/gfm-render.sh b/gfm-render.sh index 88970dd15..7a3df636c 100755 --- a/gfm-render.sh +++ b/gfm-render.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash USERNAME="raywenderlich" +TOKEN="e64530973ec12f12c94ac26cce8c93caf466fc89" # $1 - readme function render_markdown_to_html { From 0c2aa34b5a93e4e5ecf18b451ecae932f480d8ad Mon Sep 17 00:00:00 2001 From: vincentngo Date: Fri, 17 Nov 2017 17:45:19 -0500 Subject: [PATCH 016/327] revoke token --- gfm-render.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/gfm-render.sh b/gfm-render.sh index 7a3df636c..09c026d55 100755 --- a/gfm-render.sh +++ b/gfm-render.sh @@ -1,8 +1,5 @@ #!/usr/bin/env bash -USERNAME="raywenderlich" -TOKEN="e64530973ec12f12c94ac26cce8c93caf466fc89" - # $1 - readme function render_markdown_to_html { # escape escaping characters From d7f172a8db597a7c699679b9b9977bede7469487 Mon Sep 17 00:00:00 2001 From: remlostime Date: Sun, 23 Jul 2017 13:13:39 -0700 Subject: [PATCH 017/327] Improvement of Apple Ordered Set Add explaination for apple ordered set --- .../AppleOrderedSet.playground/Contents.swift | 13 +- .../Sources/AppleOrderedSet.swift | 4 + Ordered Set/AppleOrderedSet.swift | 4 + Ordered Set/README.markdown | 126 +++++++++++++++++- .../contents.xcworkspacedata | 8 +- 5 files changed, 144 insertions(+), 11 deletions(-) diff --git a/Ordered Set/AppleOrderedSet.playground/Contents.swift b/Ordered Set/AppleOrderedSet.playground/Contents.swift index 4388c664b..c5548c2c2 100644 --- a/Ordered Set/AppleOrderedSet.playground/Contents.swift +++ b/Ordered Set/AppleOrderedSet.playground/Contents.swift @@ -6,8 +6,17 @@ s.add(-1) s.add(0) s.insert(4, at: 3) -s.set(-1, at: 0) +print(s.all()) // [1, 2, -1, 4, 0] + +s.set(-1, at: 0) // We already have -1 in index: 2, so we will do nothing here + +print(s.all()) // [1, 2, -1, 4, 0] + s.remove(-1) -print(s.object(at: 1)) +print(s.all()) // [1, 2, 4, 0] + +print(s.object(at: 1)) // 2 + +print(s.object(at: 2)) // 4 diff --git a/Ordered Set/AppleOrderedSet.playground/Sources/AppleOrderedSet.swift b/Ordered Set/AppleOrderedSet.playground/Sources/AppleOrderedSet.swift index 3ff19cb8d..6bd8f94a0 100644 --- a/Ordered Set/AppleOrderedSet.playground/Sources/AppleOrderedSet.swift +++ b/Ordered Set/AppleOrderedSet.playground/Sources/AppleOrderedSet.swift @@ -69,4 +69,8 @@ public class AppleOrderedSet { indexOfKey[objects[i]] = i } } + + public func all() -> [T] { + return objects + } } diff --git a/Ordered Set/AppleOrderedSet.swift b/Ordered Set/AppleOrderedSet.swift index 3ff19cb8d..6bd8f94a0 100644 --- a/Ordered Set/AppleOrderedSet.swift +++ b/Ordered Set/AppleOrderedSet.swift @@ -69,4 +69,8 @@ public class AppleOrderedSet { indexOfKey[objects[i]] = i } } + + public func all() -> [T] { + return objects + } } diff --git a/Ordered Set/README.markdown b/Ordered Set/README.markdown index bc5003a61..11096d5bb 100644 --- a/Ordered Set/README.markdown +++ b/Ordered Set/README.markdown @@ -1,5 +1,7 @@ # Ordered Set +## Sorted Array Version + An Ordered Set is a collection of unique items in sorted order. Items are usually sorted from least to greatest. The Ordered Set data type is a hybrid of: @@ -323,15 +325,129 @@ The right side did not contain the item, so we look at the left side: [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] * mid - + [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] * mid Finally, we've found `Player 2`, and return index 3. -## See Also +## Apple's Ordered Set +Below the ordered set is based on sorted array. But [Apple's version](https://developer.apple.com/documentation/foundation/nsorderedset), it's pretty different. Now, let's look into how to implement apple's ordered set. + +Here is the example about how it works + +```swift +let s = AppleOrderedSet() + +s.add(1) +s.add(2) +s.add(-1) +s.add(0) +s.insert(4, at: 3) + +print(s.all()) // [1, 2, -1, 4, 0] + +s.set(-1, at: 0) // We already have -1 in index: 2, so we will do nothing here + +print(s.all()) // [1, 2, -1, 4, 0] + +s.remove(-1) + +print(s.all()) // [1, 2, 4, 0] + +print(s.object(at: 1)) // 2 + +print(s.object(at: 2)) // 4 +``` + +The significant difference is the the array is not sorted. The elements in the array are the same when insert them. Image the array without duplicates and with `O(logn)` or `O(1)` search time. + +The idea here is using a data structure to provide `O(1)` or `O(logn)` time complexity, so it's easy to think about hash table. + +```swift +var indexOfKey: [T: Int] +var objects: [T] +``` + +`indexOfKey` is used to track the index of the element. `objects` is array holding elements. + +We will go through some key functions details here. + +### Add -[Apple Ordered Set](AppleOrderedSet.playground) -@remlostime added an Apple version of `OrderedSet` +Update `indexOfKey` and insert element in the end of `objects` + +```swift +// O(1) +public func add(_ object: T) { + guard indexOfKey[object] == nil else { + return + } + + objects.append(object) + indexOfKey[object] = objects.count - 1 +} +``` + +### Insert + +Insert in a random place of the array will cost `O(n)` time. + +```swift +// O(n) +public func insert(_ object: T, at index: Int) { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return + } + + objects.insert(object, at: index) + indexOfKey[object] = index + for i in index+1..= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return + } + + indexOfKey.removeValue(forKey: objects[index]) + indexOfKey[object] = index + objects[index] = object +} +``` + +### Remove + +Remove element in the array will cost `O(n)`. At the same time, we need to update all elements's index after the removed element. + +```swift +// O(n) +public func remove(_ object: T) { + guard let index = indexOfKey[object] else { + return + } + + indexOfKey.removeValue(forKey: object) + objects.remove(at: index) + for i in index.. + location = "group:AppleOrderedSet.playground"> + location = "group:AppleOrderedSet.swift"> + location = "group:OrderedSet.playground"> + location = "group:OrderedSet.swift"> From 95b45f038bfaba63fac2621c24dd3bd0bd9d59be Mon Sep 17 00:00:00 2001 From: remlostime Date: Sat, 18 Nov 2017 20:08:36 -0800 Subject: [PATCH 018/327] Split sorted set and ordered set --- .../Sources/AppleOrderedSet.swift | 76 ---- .../contents.xcplayground | 4 - Ordered Set/AppleOrderedSet.swift | 76 ---- .../Contents.swift | 2 +- .../timeline.xctimeline | 6 - .../Sources/OrderedSet.swift | 171 ++++----- .../contents.xcplayground | 8 +- Ordered Set/OrderedSet.swift | 172 ++++----- Ordered Set/README.markdown | 336 +----------------- Sorted Set/README.markdown | 334 +++++++++++++++++ .../Example 1.xcplaygroundpage/Contents.swift | 2 +- .../timeline.xctimeline | 6 +- .../Example 2.xcplaygroundpage/Contents.swift | 2 +- .../Example 3.xcplaygroundpage/Contents.swift | 2 +- .../Sources/Player.swift | 6 +- .../Sources/Random.swift | 4 +- .../Sources/SortedSet.swift | 118 ++++++ .../contents.xcplayground | 8 + .../contents.xcworkspacedata | 0 Sorted Set/SortedSet.swift | 118 ++++++ .../contents.xcworkspacedata | 19 +- 21 files changed, 738 insertions(+), 732 deletions(-) delete mode 100644 Ordered Set/AppleOrderedSet.playground/Sources/AppleOrderedSet.swift delete mode 100644 Ordered Set/AppleOrderedSet.playground/contents.xcplayground delete mode 100644 Ordered Set/AppleOrderedSet.swift rename Ordered Set/{AppleOrderedSet.playground => OrderedSet.playground}/Contents.swift (91%) delete mode 100644 Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/timeline.xctimeline create mode 100644 Sorted Set/README.markdown rename {Ordered Set/OrderedSet.playground => Sorted Set/SortedSet.playground}/Pages/Example 1.xcplaygroundpage/Contents.swift (94%) rename {Ordered Set/OrderedSet.playground => Sorted Set/SortedSet.playground}/Pages/Example 1.xcplaygroundpage/timeline.xctimeline (50%) rename {Ordered Set/OrderedSet.playground => Sorted Set/SortedSet.playground}/Pages/Example 2.xcplaygroundpage/Contents.swift (95%) rename {Ordered Set/OrderedSet.playground => Sorted Set/SortedSet.playground}/Pages/Example 3.xcplaygroundpage/Contents.swift (95%) rename {Ordered Set/OrderedSet.playground => Sorted Set/SortedSet.playground}/Sources/Player.swift (95%) rename {Ordered Set/OrderedSet.playground => Sorted Set/SortedSet.playground}/Sources/Random.swift (88%) create mode 100644 Sorted Set/SortedSet.playground/Sources/SortedSet.swift create mode 100644 Sorted Set/SortedSet.playground/contents.xcplayground rename {Ordered Set/OrderedSet.playground => Sorted Set/SortedSet.playground}/playground.xcworkspace/contents.xcworkspacedata (100%) create mode 100644 Sorted Set/SortedSet.swift diff --git a/Ordered Set/AppleOrderedSet.playground/Sources/AppleOrderedSet.swift b/Ordered Set/AppleOrderedSet.playground/Sources/AppleOrderedSet.swift deleted file mode 100644 index 6bd8f94a0..000000000 --- a/Ordered Set/AppleOrderedSet.playground/Sources/AppleOrderedSet.swift +++ /dev/null @@ -1,76 +0,0 @@ -public class AppleOrderedSet { - private var objects: [T] = [] - private var indexOfKey: [T: Int] = [:] - - public init() {} - - // O(1) - public func add(_ object: T) { - guard indexOfKey[object] == nil else { - return - } - - objects.append(object) - indexOfKey[object] = objects.count - 1 - } - - // O(n) - public func insert(_ object: T, at index: Int) { - assert(index < objects.count, "Index should be smaller than object count") - assert(index >= 0, "Index should be bigger than 0") - - guard indexOfKey[object] == nil else { - return - } - - objects.insert(object, at: index) - indexOfKey[object] = index - for i in index+1.. T { - assert(index < objects.count, "Index should be smaller than object count") - assert(index >= 0, "Index should be bigger than 0") - - return objects[index] - } - - // O(1) - public func set(_ object: T, at index: Int) { - assert(index < objects.count, "Index should be smaller than object count") - assert(index >= 0, "Index should be bigger than 0") - - guard indexOfKey[object] == nil else { - return - } - - indexOfKey.removeValue(forKey: objects[index]) - indexOfKey[object] = index - objects[index] = object - } - - // O(1) - public func indexOf(_ object: T) -> Int { - return indexOfKey[object] ?? -1 - } - - // O(n) - public func remove(_ object: T) { - guard let index = indexOfKey[object] else { - return - } - - indexOfKey.removeValue(forKey: object) - objects.remove(at: index) - for i in index.. [T] { - return objects - } -} diff --git a/Ordered Set/AppleOrderedSet.playground/contents.xcplayground b/Ordered Set/AppleOrderedSet.playground/contents.xcplayground deleted file mode 100644 index 5da2641c9..000000000 --- a/Ordered Set/AppleOrderedSet.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Ordered Set/AppleOrderedSet.swift b/Ordered Set/AppleOrderedSet.swift deleted file mode 100644 index 6bd8f94a0..000000000 --- a/Ordered Set/AppleOrderedSet.swift +++ /dev/null @@ -1,76 +0,0 @@ -public class AppleOrderedSet { - private var objects: [T] = [] - private var indexOfKey: [T: Int] = [:] - - public init() {} - - // O(1) - public func add(_ object: T) { - guard indexOfKey[object] == nil else { - return - } - - objects.append(object) - indexOfKey[object] = objects.count - 1 - } - - // O(n) - public func insert(_ object: T, at index: Int) { - assert(index < objects.count, "Index should be smaller than object count") - assert(index >= 0, "Index should be bigger than 0") - - guard indexOfKey[object] == nil else { - return - } - - objects.insert(object, at: index) - indexOfKey[object] = index - for i in index+1.. T { - assert(index < objects.count, "Index should be smaller than object count") - assert(index >= 0, "Index should be bigger than 0") - - return objects[index] - } - - // O(1) - public func set(_ object: T, at index: Int) { - assert(index < objects.count, "Index should be smaller than object count") - assert(index >= 0, "Index should be bigger than 0") - - guard indexOfKey[object] == nil else { - return - } - - indexOfKey.removeValue(forKey: objects[index]) - indexOfKey[object] = index - objects[index] = object - } - - // O(1) - public func indexOf(_ object: T) -> Int { - return indexOfKey[object] ?? -1 - } - - // O(n) - public func remove(_ object: T) { - guard let index = indexOfKey[object] else { - return - } - - indexOfKey.removeValue(forKey: object) - objects.remove(at: index) - for i in index.. [T] { - return objects - } -} diff --git a/Ordered Set/AppleOrderedSet.playground/Contents.swift b/Ordered Set/OrderedSet.playground/Contents.swift similarity index 91% rename from Ordered Set/AppleOrderedSet.playground/Contents.swift rename to Ordered Set/OrderedSet.playground/Contents.swift index c5548c2c2..6a2415231 100644 --- a/Ordered Set/AppleOrderedSet.playground/Contents.swift +++ b/Ordered Set/OrderedSet.playground/Contents.swift @@ -1,4 +1,4 @@ -let s = AppleOrderedSet() +let s = OrderedSet() s.add(1) s.add(2) diff --git a/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/timeline.xctimeline b/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift b/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift index 8490a3320..5508c3637 100644 --- a/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift +++ b/Ordered Set/OrderedSet.playground/Sources/OrderedSet.swift @@ -1,117 +1,76 @@ -/* - An Ordered Set is a collection where all items in the set follow an ordering, - usually ordered from 'least' to 'most'. The way you value and compare items - can be user-defined. -*/ -public struct OrderedSet { - private var internalSet = [T]() - - public init() { } - - // Returns the number of elements in the OrderedSet. - public var count: Int { - return internalSet.count - } - - // Inserts an item. Performance: O(n) - public mutating func insert(_ item: T) { - if exists(item) { - return // don't add an item if it already exists - } - - // Insert new the item just before the one that is larger. - for i in 0.. item { - internalSet.insert(item, at: i) - return - } +public class OrderedSet { + private var objects: [T] = [] + private var indexOfKey: [T: Int] = [:] + + public init() {} + + // O(1) + public func add(_ object: T) { + guard indexOfKey[object] == nil else { + return } - - // Append to the back if the new item is greater than any other in the set. - internalSet.append(item) + + objects.append(object) + indexOfKey[object] = objects.count - 1 } - - // Removes an item if it exists. Performance: O(n) - public mutating func remove(_ item: T) { - if let index = index(of: item) { - internalSet.remove(at: index) + + // O(n) + public func insert(_ object: T, at index: Int) { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return } - } - - // Returns true if and only if the item exists somewhere in the set. - public func exists(_ item: T) -> Bool { - return index(of: item) != nil - } - - // Returns the index of an item if it exists, or -1 otherwise. - public func index(of item: T) -> Int? { - var leftBound = 0 - var rightBound = count - 1 - - while leftBound <= rightBound { - let mid = leftBound + ((rightBound - leftBound) / 2) - - if internalSet[mid] > item { - rightBound = mid - 1 - } else if internalSet[mid] < item { - leftBound = mid + 1 - } else if internalSet[mid] == item { - return mid - } else { - // When we get here, we've landed on an item whose value is equal to the - // value of the item we're looking for, but the items themselves are not - // equal. We need to check the items with the same value to the right - // and to the left in order to find an exact match. - - // Check to the right. - for j in stride(from: mid, to: count - 1, by: 1) { - if internalSet[j + 1] == item { - return j + 1 - } else if internalSet[j] < internalSet[j + 1] { - break - } - } - - // Check to the left. - for j in stride(from: mid, to: 0, by: -1) { - if internalSet[j - 1] == item { - return j - 1 - } else if internalSet[j] > internalSet[j - 1] { - break - } - } - return nil - } + + objects.insert(object, at: index) + indexOfKey[object] = index + for i in index+1.. T { - assert(index >= 0 && index < count) - return internalSet[index] + + // O(1) + public func object(at index: Int) -> T { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + return objects[index] } - - // Returns the 'maximum' or 'largest' value in the set. - public func max() -> T? { - return count == 0 ? nil : internalSet[count - 1] + + // O(1) + public func set(_ object: T, at index: Int) { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return + } + + indexOfKey.removeValue(forKey: objects[index]) + indexOfKey[object] = index + objects[index] = object } - - // Returns the 'minimum' or 'smallest' value in the set. - public func min() -> T? { - return count == 0 ? nil : internalSet[0] + + // O(1) + public func indexOf(_ object: T) -> Int { + return indexOfKey[object] ?? -1 } - - // Returns the k-th largest element in the set, if k is in the range - // [1, count]. Returns nil otherwise. - public func kLargest(_ k: Int) -> T? { - return k > count || k <= 0 ? nil : internalSet[count - k] + + // O(n) + public func remove(_ object: T) { + guard let index = indexOfKey[object] else { + return + } + + indexOfKey.removeValue(forKey: object) + objects.remove(at: index) + for i in index.. T? { - return k > count || k <= 0 ? nil : internalSet[k - 1] + + public func all() -> [T] { + return objects } } diff --git a/Ordered Set/OrderedSet.playground/contents.xcplayground b/Ordered Set/OrderedSet.playground/contents.xcplayground index 18c02c912..5da2641c9 100644 --- a/Ordered Set/OrderedSet.playground/contents.xcplayground +++ b/Ordered Set/OrderedSet.playground/contents.xcplayground @@ -1,8 +1,4 @@ - - - - - - + + \ No newline at end of file diff --git a/Ordered Set/OrderedSet.swift b/Ordered Set/OrderedSet.swift index a8b3b0966..8b6df7d3e 100644 --- a/Ordered Set/OrderedSet.swift +++ b/Ordered Set/OrderedSet.swift @@ -1,117 +1,77 @@ -/* - An Ordered Set is a collection where all items in the set follow an ordering, - usually ordered from 'least' to 'most'. The way you value and compare items - can be user-defined. -*/ -public struct OrderedSet { - private var internalSet = [T]() - - public init() { } - - // Returns the number of elements in the OrderedSet. - public var count: Int { - return internalSet.count - } - - // Inserts an item. Performance: O(n) - public mutating func insert(item: T) { - if exists(item) { - return // don't add an item if it already exists +public class OrderedSet { + private var objects: [T] = [] + private var indexOfKey: [T: Int] = [:] + + public init() {} + + // O(1) + public func add(_ object: T) { + guard indexOfKey[object] == nil else { + return } - - // Insert new the item just before the one that is larger. - for i in 0.. item { - internalSet.insert(item, atIndex: i) - return - } - } - - // Append to the back if the new item is greater than any other in the set. - internalSet.append(item) + + objects.append(object) + indexOfKey[object] = objects.count - 1 } - - // Removes an item if it exists. Performance: O(n) - public mutating func remove(item: T) { - if let index = indexOf(item) { - internalSet.removeAtIndex(index) + + // O(n) + public func insert(_ object: T, at index: Int) { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return } - } - - // Returns true if and only if the item exists somewhere in the set. - public func exists(item: T) -> Bool { - return indexOf(item) != nil - } - - // Returns the index of an item if it exists, or -1 otherwise. - public func indexOf(item: T) -> Int? { - var leftBound = 0 - var rightBound = count - 1 - - while leftBound <= rightBound { - let mid = leftBound + ((rightBound - leftBound) / 2) - - if internalSet[mid] > item { - rightBound = mid - 1 - } else if internalSet[mid] < item { - leftBound = mid + 1 - } else if internalSet[mid] == item { - return mid - } else { - // When we get here, we've landed on an item whose value is equal to the - // value of the item we're looking for, but the items themselves are not - // equal. We need to check the items with the same value to the right - // and to the left in order to find an exact match. - - // Check to the right. - for j in mid.stride(to: count - 1, by: 1) { - if internalSet[j + 1] == item { - return j + 1 - } else if internalSet[j] < internalSet[j + 1] { - break - } - } - - // Check to the left. - for j in mid.stride(to: 0, by: -1) { - if internalSet[j - 1] == item { - return j - 1 - } else if internalSet[j] > internalSet[j - 1] { - break - } - } - return nil - } + + objects.insert(object, at: index) + indexOfKey[object] = index + for i in index+1.. T { - assert(index >= 0 && index < count) - return internalSet[index] + + // O(1) + public func object(at index: Int) -> T { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + return objects[index] } - - // Returns the 'maximum' or 'largest' value in the set. - public func max() -> T? { - return count == 0 ? nil : internalSet[count - 1] + + // O(1) + public func set(_ object: T, at index: Int) { + assert(index < objects.count, "Index should be smaller than object count") + assert(index >= 0, "Index should be bigger than 0") + + guard indexOfKey[object] == nil else { + return + } + + indexOfKey.removeValue(forKey: objects[index]) + indexOfKey[object] = index + objects[index] = object } - - // Returns the 'minimum' or 'smallest' value in the set. - public func min() -> T? { - return count == 0 ? nil : internalSet[0] + + // O(1) + public func indexOf(_ object: T) -> Int { + return indexOfKey[object] ?? -1 } - - // Returns the k-th largest element in the set, if k is in the range - // [1, count]. Returns nil otherwise. - public func kLargest(k: Int) -> T? { - return k > count || k <= 0 ? nil : internalSet[count - k] + + // O(n) + public func remove(_ object: T) { + guard let index = indexOfKey[object] else { + return + } + + indexOfKey.removeValue(forKey: object) + objects.remove(at: index) + for i in index.. T? { - return k > count || k <= 0 ? nil : internalSet[k - 1] + + public func all() -> [T] { + return objects } } + diff --git a/Ordered Set/README.markdown b/Ordered Set/README.markdown index 11096d5bb..82d736731 100644 --- a/Ordered Set/README.markdown +++ b/Ordered Set/README.markdown @@ -1,338 +1,6 @@ # Ordered Set -## Sorted Array Version - -An Ordered Set is a collection of unique items in sorted order. Items are usually sorted from least to greatest. - -The Ordered Set data type is a hybrid of: - -- a [Set](https://en.wikipedia.org/wiki/Set_%28mathematics%29), a collection of unique items where the order does not matter, and -- a [Sequence](https://en.wikipedia.org/wiki/Sequence), an ordered list of items where each item may appear more than once. - -It's important to keep in mind that two items can have the same *value* but still may not be equal. For example, we could define "a" and "z" to have the same value (their lengths), but clearly "a" != "z". - -## Why use an ordered set? - -Ordered Sets should be considered when you need to keep your collection sorted at all times, and you do lookups on the collection much more frequently than inserting or deleting items. Many of the lookup operations for an Ordered Set are **O(1)**. - -A good example would be keeping track of the rankings of players in a scoreboard (see example 2 below). - -#### These are ordered sets - -A set of integers: - - [1, 2, 3, 6, 8, 10, 1000] - -A set of strings: - - ["a", "is", "set", "this"] - -The "value" of these strings could be their text content, but also for example their length. - -#### These are not ordered sets - -This set violates the property of uniqueness: - - [1, 1, 2, 3, 5, 8] - -This set violates the sorted property: - - [1, 11, 2, 3] - -## The code - -We'll start by creating our internal representation for the Ordered Set. Since the idea of a set is similar to that of an array, we will use an array to represent our set. Furthermore, since we'll need to keep the set sorted, we need to be able to compare the individual elements. Thus, any type must conform to the [Comparable Protocol](https://developer.apple.com/library/watchos/documentation/Swift/Reference/Swift_Comparable_Protocol/index.html). - -```swift -public struct OrderedSet { - private var internalSet = [T]() - - // Returns the number of elements in the OrderedSet. - public var count: Int { - return internalSet.count - } - ... -``` - -Lets take a look at the `insert()` function first. This first checks if the item already exists in the collection. If so, it returns and does not insert the item. Otherwise, it will insert the item through straightforward iteration. - -```swift - public mutating func insert(_ item: T){ - if exists(item) { - return // don't add an item if it already exists - } - - // Insert new the item just before the one that is larger. - for i in 0.. item { - internalSet.insert(item, at: i) - return - } - } - - // Append to the back if the new item is greater than any other in the set. - internalSet.append(item) - } -``` - -As we'll see later on, checking if the item is already in the set has an efficiency of **O(log(n) + k)** where **k** is the number of items with the same value as the item we are inserting. - -To insert the new item, the `for` loop starts from the beginning of the array, and checks to see if each item is larger than the item we want to insert. Once we find such an item, we insert the new one into its place. This shifts the rest of the array over to the right by 1 position. This loop is at worst **O(n)**. - -The total performance of the `insert()` function is therefore **O(n)**. - -Next up is the `remove()` function: - -```swift - public mutating func remove(_ item: T) { - if let index = index(of: item) { - internalSet.remove(at: index) - } - } -``` - -First this checks if the item exists and then removes it from the array. Because of the `removeAtIndex()` function, the efficiency for remove is **O(n)**. - -The next function is `indexOf()`, which takes in an object of type `T` and returns the index of the corresponding item if it is in the set, or `nil` if it is not. Since our set is sorted, we can use a binary search to quickly search for the item. - -```swift - public func index(of item: T) -> Int? { - var leftBound = 0 - var rightBound = count - 1 - - while leftBound <= rightBound { - let mid = leftBound + ((rightBound - leftBound) / 2) - - if internalSet[mid] > item { - rightBound = mid - 1 - } else if internalSet[mid] < item { - leftBound = mid + 1 - } else if internalSet[mid] == item { - return mid - } else { - // see below - } - } - return nil - } -``` - -> **Note:** If you are not familiar with the concept of binary search, we have an [article that explains all about it](../Binary%20Search). - -However, there is an important issue to deal with here. Recall that two objects can be unequal yet still have the same "value" for the purposes of comparing them. Since a set can contain multiple items with the same value, it is important to check that the binary search has landed on the correct item. - -For example, consider this ordered set of `Player` objects. Each `Player` has a name and a number of points: - - [ ("Bill", 50), ("Ada", 50), ("Jony", 50), ("Steve", 200), ("Jean-Louis", 500), ("Woz", 1000) ] - -We want the set to be ordered by points, from low to high. Multiple players can have the same number of points. The name of the player is not important for this ordering. However, the name *is* important for retrieving the correct item. - -Let's say we do `indexOf(bill)` where `bill` is player object `("Bill", 50)`. If we did a traditional binary search we'd land on index 2, which is the object `("Jony", 50)`. The value 50 matches, but it's not the object we're looking for! - -Therefore, we also need to check the items with the same value to the right and left of the midpoint. The code to check the left and right side looks like this: - -```swift - // Check to the right. - for j in mid.stride(to: count - 1, by: 1) { - if internalSet[j + 1] == item { - return j + 1 - } else if internalSet[j] < internalSet[j + 1] { - break - } - } - - // Check to the left. - for j in mid.stride(to: 0, by: -1) { - if internalSet[j - 1] == item { - return j - 1 - } else if internalSet[j] > internalSet[j - 1] { - break - } - } - - return nil -``` - -These loops start at the current `mid` value and then look at the neighboring values until we've found the correct object. - -The combined runtime for `indexOf()` is **O(log(n) + k)** where **n** is the length of the set, and **k** is the number of items with the same *value* as the one that is being searched for. - -Since the set is sorted, the following operations are all **O(1)**: - -```swift - // Returns the 'maximum' or 'largest' value in the set. - public func max() -> T? { - return count == 0 ? nil : internalSet[count - 1] - } - - // Returns the 'minimum' or 'smallest' value in the set. - public func min() -> T? { - return count == 0 ? nil : internalSet[0] - } - - // Returns the k-th largest element in the set, if k is in the range - // [1, count]. Returns nil otherwise. - public func kLargest(_ k: Int) -> T? { - return k > count || k <= 0 ? nil : internalSet[count - k] - } - - // Returns the k-th smallest element in the set, if k is in the range - // [1, count]. Returns nil otherwise. - public func kSmallest(_ k: Int) -> T? { - return k > count || k <= 0 ? nil : internalSet[k - 1] - } -``` - -## Examples - -Below are a few examples that can be found in the playground file. - -### Example 1 - -Here we create a set with random Integers. Printing the largest/smallest 5 numbers in the set is fairly easy. - -```swift -// Example 1 with type Int -var mySet = OrderedSet() - -// Insert random numbers into the set -for _ in 0..<50 { - mySet.insert(randomNum(50, max: 500)) -} - -print(mySet) - -print(mySet.max()) -print(mySet.min()) - -// Print the 5 largest values -for k in 1...5 { - print(mySet.kLargest(k)) -} - -// Print the 5 lowest values -for k in 1...5 { - print(mySet.kSmallest(k)) -} -``` - -### Example 2 - -In this example we take a look at something a bit more interesting. We define a `Player` struct as follows: - -```swift -public struct Player: Comparable { - public var name: String - public var points: Int -} -``` - -The `Player` also gets its own `==` and `<` operators. The `<` operator is used to determine the sort order of the set, while `==` determines whether two objects are really equal. - -Note that `==` compares both the name and the points: - -```swifr -func ==(x: Player, y: Player) -> Bool { - return x.name == y.name && x.points == y.points -} -``` - -But `<` only compares the points: - -```swift -func <(x: Player, y: Player) -> Bool { - return x.points < y.points -} -``` - -Therefore, two `Player`s can each have the same value (the number of points), but are not guaranteed to be equal (they can have different names). - -We create a new set and insert 20 random players. The `Player()` constructor gives each player a random name and score: - -```swift -var playerSet = OrderedSet() - -// Populate the set with random players. -for _ in 0..<20 { - playerSet.insert(Player()) -} -``` - -Insert another player: - -```swift -var anotherPlayer = Player() -playerSet.insert(anotherPlayer) -``` - -Now we use the `indexOf()` function to find out what rank `anotherPlayer` is. - -```swift -let level = playerSet.count - playerSet.indexOf(anotherPlayer)! -print("\(anotherPlayer.name) is ranked at level \(level) with \(anotherPlayer.points) points") -``` - -### Example 3 - -The final example demonstrates the need to look for the right item even after the binary search has completed. - -We insert 9 players into the set: - -```swift -var repeatedSet = OrderedSet() - -repeatedSet.insert(Player(name: "Player 1", points: 100)) -repeatedSet.insert(Player(name: "Player 2", points: 100)) -repeatedSet.insert(Player(name: "Player 3", points: 100)) -repeatedSet.insert(Player(name: "Player 4", points: 100)) -repeatedSet.insert(Player(name: "Player 5", points: 100)) -repeatedSet.insert(Player(name: "Player 6", points: 50)) -repeatedSet.insert(Player(name: "Player 7", points: 200)) -repeatedSet.insert(Player(name: "Player 8", points: 250)) -repeatedSet.insert(Player(name: "Player 9", points: 25)) -``` - -Notice how several of these players have the same value of 100 points. - -The set looks something like this: - - [Player 9, Player 6, Player 1, Player 2, Player 3, Player 4, Player 5, Player 7, Player 8] - -The next line looks for `Player 2`: - -```swift -print(repeatedSet.index(of: Player(name: "Player 2", points: 100))) -``` - -After the binary search finishes, the value of `mid` is at index 5: - - [Player 9, Player 6, Player 1, Player 2, Player 3, Player 4, Player 5, Player 7, Player 8] - mid - -However, this is not `Player 2`. Both `Player 4` and `Player 2` have the same points, but a different name. The binary search only looked at the points, not the name. - -But we do know that `Player 2` must be either to the immediate left or the right of `Player 4`, so we check both sides of `mid`. We only need to look at the objects with the same value as `Player 4`. The others are replaced by `X`: - - [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] - mid - -The code then first checks on the right of `mid` (where the `*` is): - - [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] - mid * - -The right side did not contain the item, so we look at the left side: - - [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] - * mid - - [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] - * mid - -Finally, we've found `Player 2`, and return index 3. - -## Apple's Ordered Set -Below the ordered set is based on sorted array. But [Apple's version](https://developer.apple.com/documentation/foundation/nsorderedset), it's pretty different. Now, let's look into how to implement apple's ordered set. +Let's look into how to implement [Ordered Set](https://developer.apple.com/documentation/foundation/nsorderedset). Here is the example about how it works @@ -450,4 +118,4 @@ public func remove(_ object: T) { } ``` -*Ordered Set is Written By Zain Humayun, Apple Ordered Set is Written By Kai Chen* +*Written By Kai Chen* diff --git a/Sorted Set/README.markdown b/Sorted Set/README.markdown new file mode 100644 index 000000000..a8b5ad1ea --- /dev/null +++ b/Sorted Set/README.markdown @@ -0,0 +1,334 @@ +# Sorted Set + +## Sorted Array Version + +An Sorted Set is a collection of unique items in sorted order. Items are usually sorted from least to greatest. + +The Sorted Set data type is a hybrid of: + +- a [Set](https://en.wikipedia.org/wiki/Set_%28mathematics%29), a collection of unique items where the order does not matter, and +- a [Sequence](https://en.wikipedia.org/wiki/Sequence), an sorted list of items where each item may appear more than once. + +It's important to keep in mind that two items can have the same *value* but still may not be equal. For example, we could define "a" and "z" to have the same value (their lengths), but clearly "a" != "z". + +## Why use an sorted set? + +Sorted Sets should be considered when you need to keep your collection sorted at all times, and you do lookups on the collection much more frequently than inserting or deleting items. Many of the lookup operations for an Sorted Set are **O(1)**. + +A good example would be keeping track of the rankings of players in a scoreboard (see example 2 below). + +#### These are sorted sets + +A set of integers: + + [1, 2, 3, 6, 8, 10, 1000] + +A set of strings: + + ["a", "is", "set", "this"] + +The "value" of these strings could be their text content, but also for example their length. + +#### These are not sorted sets + +This set violates the property of uniqueness: + + [1, 1, 2, 3, 5, 8] + +This set violates the sorted property: + + [1, 11, 2, 3] + +## The code + +We'll start by creating our internal representation for the Sorted Set. Since the idea of a set is similar to that of an array, we will use an array to represent our set. Furthermore, since we'll need to keep the set sorted, we need to be able to compare the individual elements. Thus, any type must conform to the [Comparable Protocol](https://developer.apple.com/library/watchos/documentation/Swift/Reference/Swift_Comparable_Protocol/index.html). + +```swift +public struct SortedSet { + private var internalSet = [T]() + + // Returns the number of elements in the SortedSet. + public var count: Int { + return internalSet.count + } + ... +``` + +Lets take a look at the `insert()` function first. This first checks if the item already exists in the collection. If so, it returns and does not insert the item. Otherwise, it will insert the item through straightforward iteration. + +```swift + public mutating func insert(_ item: T){ + if exists(item) { + return // don't add an item if it already exists + } + + // Insert new the item just before the one that is larger. + for i in 0.. item { + internalSet.insert(item, at: i) + return + } + } + + // Append to the back if the new item is greater than any other in the set. + internalSet.append(item) + } +``` + +As we'll see later on, checking if the item is already in the set has an efficiency of **O(log(n) + k)** where **k** is the number of items with the same value as the item we are inserting. + +To insert the new item, the `for` loop starts from the beginning of the array, and checks to see if each item is larger than the item we want to insert. Once we find such an item, we insert the new one into its place. This shifts the rest of the array over to the right by 1 position. This loop is at worst **O(n)**. + +The total performance of the `insert()` function is therefore **O(n)**. + +Next up is the `remove()` function: + +```swift + public mutating func remove(_ item: T) { + if let index = index(of: item) { + internalSet.remove(at: index) + } + } +``` + +First this checks if the item exists and then removes it from the array. Because of the `removeAtIndex()` function, the efficiency for remove is **O(n)**. + +The next function is `indexOf()`, which takes in an object of type `T` and returns the index of the corresponding item if it is in the set, or `nil` if it is not. Since our set is sorted, we can use a binary search to quickly search for the item. + +```swift + public func index(of item: T) -> Int? { + var leftBound = 0 + var rightBound = count - 1 + + while leftBound <= rightBound { + let mid = leftBound + ((rightBound - leftBound) / 2) + + if internalSet[mid] > item { + rightBound = mid - 1 + } else if internalSet[mid] < item { + leftBound = mid + 1 + } else if internalSet[mid] == item { + return mid + } else { + // see below + } + } + return nil + } +``` + +> **Note:** If you are not familiar with the concept of binary search, we have an [article that explains all about it](../Binary%20Search). + +However, there is an important issue to deal with here. Recall that two objects can be unequal yet still have the same "value" for the purposes of comparing them. Since a set can contain multiple items with the same value, it is important to check that the binary search has landed on the correct item. + +For example, consider this sorted set of `Player` objects. Each `Player` has a name and a number of points: + + [ ("Bill", 50), ("Ada", 50), ("Jony", 50), ("Steve", 200), ("Jean-Louis", 500), ("Woz", 1000) ] + +We want the set to be sorted by points, from low to high. Multiple players can have the same number of points. The name of the player is not important for this ordering. However, the name *is* important for retrieving the correct item. + +Let's say we do `indexOf(bill)` where `bill` is player object `("Bill", 50)`. If we did a traditional binary search we'd land on index 2, which is the object `("Jony", 50)`. The value 50 matches, but it's not the object we're looking for! + +Therefore, we also need to check the items with the same value to the right and left of the midpoint. The code to check the left and right side looks like this: + +```swift + // Check to the right. + for j in mid.stride(to: count - 1, by: 1) { + if internalSet[j + 1] == item { + return j + 1 + } else if internalSet[j] < internalSet[j + 1] { + break + } + } + + // Check to the left. + for j in mid.stride(to: 0, by: -1) { + if internalSet[j - 1] == item { + return j - 1 + } else if internalSet[j] > internalSet[j - 1] { + break + } + } + + return nil +``` + +These loops start at the current `mid` value and then look at the neighboring values until we've found the correct object. + +The combined runtime for `indexOf()` is **O(log(n) + k)** where **n** is the length of the set, and **k** is the number of items with the same *value* as the one that is being searched for. + +Since the set is sorted, the following operations are all **O(1)**: + +```swift + // Returns the 'maximum' or 'largest' value in the set. + public func max() -> T? { + return count == 0 ? nil : internalSet[count - 1] + } + + // Returns the 'minimum' or 'smallest' value in the set. + public func min() -> T? { + return count == 0 ? nil : internalSet[0] + } + + // Returns the k-th largest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kLargest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[count - k] + } + + // Returns the k-th smallest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kSmallest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[k - 1] + } +``` + +## Examples + +Below are a few examples that can be found in the playground file. + +### Example 1 + +Here we create a set with random Integers. Printing the largest/smallest 5 numbers in the set is fairly easy. + +```swift +// Example 1 with type Int +var mySet = SortedSet() + +// Insert random numbers into the set +for _ in 0..<50 { + mySet.insert(randomNum(50, max: 500)) +} + +print(mySet) + +print(mySet.max()) +print(mySet.min()) + +// Print the 5 largest values +for k in 1...5 { + print(mySet.kLargest(k)) +} + +// Print the 5 lowest values +for k in 1...5 { + print(mySet.kSmallest(k)) +} +``` + +### Example 2 + +In this example we take a look at something a bit more interesting. We define a `Player` struct as follows: + +```swift +public struct Player: Comparable { + public var name: String + public var points: Int +} +``` + +The `Player` also gets its own `==` and `<` operators. The `<` operator is used to determine the sort order of the set, while `==` determines whether two objects are really equal. + +Note that `==` compares both the name and the points: + +```swifr +func ==(x: Player, y: Player) -> Bool { + return x.name == y.name && x.points == y.points +} +``` + +But `<` only compares the points: + +```swift +func <(x: Player, y: Player) -> Bool { + return x.points < y.points +} +``` + +Therefore, two `Player`s can each have the same value (the number of points), but are not guaranteed to be equal (they can have different names). + +We create a new set and insert 20 random players. The `Player()` constructor gives each player a random name and score: + +```swift +var playerSet = SortedSet() + +// Populate the set with random players. +for _ in 0..<20 { + playerSet.insert(Player()) +} +``` + +Insert another player: + +```swift +var anotherPlayer = Player() +playerSet.insert(anotherPlayer) +``` + +Now we use the `indexOf()` function to find out what rank `anotherPlayer` is. + +```swift +let level = playerSet.count - playerSet.indexOf(anotherPlayer)! +print("\(anotherPlayer.name) is ranked at level \(level) with \(anotherPlayer.points) points") +``` + +### Example 3 + +The final example demonstrates the need to look for the right item even after the binary search has completed. + +We insert 9 players into the set: + +```swift +var repeatedSet = SortedSet() + +repeatedSet.insert(Player(name: "Player 1", points: 100)) +repeatedSet.insert(Player(name: "Player 2", points: 100)) +repeatedSet.insert(Player(name: "Player 3", points: 100)) +repeatedSet.insert(Player(name: "Player 4", points: 100)) +repeatedSet.insert(Player(name: "Player 5", points: 100)) +repeatedSet.insert(Player(name: "Player 6", points: 50)) +repeatedSet.insert(Player(name: "Player 7", points: 200)) +repeatedSet.insert(Player(name: "Player 8", points: 250)) +repeatedSet.insert(Player(name: "Player 9", points: 25)) +``` + +Notice how several of these players have the same value of 100 points. + +The set looks something like this: + + [Player 9, Player 6, Player 1, Player 2, Player 3, Player 4, Player 5, Player 7, Player 8] + +The next line looks for `Player 2`: + +```swift +print(repeatedSet.index(of: Player(name: "Player 2", points: 100))) +``` + +After the binary search finishes, the value of `mid` is at index 5: + + [Player 9, Player 6, Player 1, Player 2, Player 3, Player 4, Player 5, Player 7, Player 8] + mid + +However, this is not `Player 2`. Both `Player 4` and `Player 2` have the same points, but a different name. The binary search only looked at the points, not the name. + +But we do know that `Player 2` must be either to the immediate left or the right of `Player 4`, so we check both sides of `mid`. We only need to look at the objects with the same value as `Player 4`. The others are replaced by `X`: + + [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] + mid + +The code then first checks on the right of `mid` (where the `*` is): + + [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] + mid * + +The right side did not contain the item, so we look at the left side: + + [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] + * mid + + [X, X, Player 1, Player 2, Player 3, Player 4, Player 5, X, X] + * mid + +Finally, we've found `Player 2`, and return index 3. + +*Written By Zain Humayun* diff --git a/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift similarity index 94% rename from Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift rename to Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift index c12dadf0f..45af5f99d 100644 --- a/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift +++ b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift @@ -5,7 +5,7 @@ print("Hello, Swift 4!") //: # Example 1 with type Int -var mySet = OrderedSet() +var mySet = SortedSet() // Insert random numbers into the set for _ in 0..<50 { diff --git a/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline similarity index 50% rename from Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline rename to Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline index 53114d22e..dffc42643 100644 --- a/Ordered Set/OrderedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline +++ b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Ordered Set/OrderedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift b/Sorted Set/SortedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift similarity index 95% rename from Ordered Set/OrderedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift rename to Sorted Set/SortedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift index c30260fff..2408d35d2 100644 --- a/Ordered Set/OrderedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift +++ b/Sorted Set/SortedSet.playground/Pages/Example 2.xcplaygroundpage/Contents.swift @@ -2,7 +2,7 @@ //: # Example 2 with Player objects -var playerSet = OrderedSet() +var playerSet = SortedSet() // Populate the set with random players. for _ in 0..<20 { diff --git a/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift b/Sorted Set/SortedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift similarity index 95% rename from Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift rename to Sorted Set/SortedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift index 52f154c05..63edd11d2 100644 --- a/Ordered Set/OrderedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift +++ b/Sorted Set/SortedSet.playground/Pages/Example 3.xcplaygroundpage/Contents.swift @@ -2,7 +2,7 @@ //: # Example 3: multiple entries with the same value -var repeatedSet = OrderedSet() +var repeatedSet = SortedSet() repeatedSet.insert(Player(name: "Player 1", points: 100)) repeatedSet.insert(Player(name: "Player 2", points: 100)) diff --git a/Ordered Set/OrderedSet.playground/Sources/Player.swift b/Sorted Set/SortedSet.playground/Sources/Player.swift similarity index 95% rename from Ordered Set/OrderedSet.playground/Sources/Player.swift rename to Sorted Set/SortedSet.playground/Sources/Player.swift index 26835b0a8..0960b2400 100644 --- a/Ordered Set/OrderedSet.playground/Sources/Player.swift +++ b/Sorted Set/SortedSet.playground/Sources/Player.swift @@ -3,12 +3,12 @@ public struct Player: Comparable { public var name: String public var points: Int - + public init() { self.name = String.random() self.points = random(min: 0, max: 5000) } - + public init(name: String, points: Int) { self.name = name self.points = points @@ -31,7 +31,7 @@ public func print(player: Player) { print("Player: \(player.name) | Points: \(player.points)") } -public func print(set: OrderedSet) { +public func print(set: SortedSet) { for i in 0.. String { let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" var randomString: String = "" - + for _ in 0.. { + private var internalSet = [T]() + + public init() { } + + // Returns the number of elements in the SortedSet. + public var count: Int { + return internalSet.count + } + + // Inserts an item. Performance: O(n) + public mutating func insert(_ item: T) { + if exists(item) { + return // don't add an item if it already exists + } + + // Insert new the item just before the one that is larger. + for i in 0.. item { + internalSet.insert(item, at: i) + return + } + } + + // Append to the back if the new item is greater than any other in the set. + internalSet.append(item) + } + + // Removes an item if it exists. Performance: O(n) + public mutating func remove(_ item: T) { + if let index = index(of: item) { + internalSet.remove(at: index) + } + } + + // Returns true if and only if the item exists somewhere in the set. + public func exists(_ item: T) -> Bool { + return index(of: item) != nil + } + + // Returns the index of an item if it exists, or -1 otherwise. + public func index(of item: T) -> Int? { + var leftBound = 0 + var rightBound = count - 1 + + while leftBound <= rightBound { + let mid = leftBound + ((rightBound - leftBound) / 2) + + if internalSet[mid] > item { + rightBound = mid - 1 + } else if internalSet[mid] < item { + leftBound = mid + 1 + } else if internalSet[mid] == item { + return mid + } else { + // When we get here, we've landed on an item whose value is equal to the + // value of the item we're looking for, but the items themselves are not + // equal. We need to check the items with the same value to the right + // and to the left in order to find an exact match. + + // Check to the right. + for j in stride(from: mid, to: count - 1, by: 1) { + if internalSet[j + 1] == item { + return j + 1 + } else if internalSet[j] < internalSet[j + 1] { + break + } + } + + // Check to the left. + for j in stride(from: mid, to: 0, by: -1) { + if internalSet[j - 1] == item { + return j - 1 + } else if internalSet[j] > internalSet[j - 1] { + break + } + } + return nil + } + } + return nil + } + + // Returns the item at the given index. + // Assertion fails if the index is out of the range of [0, count). + public subscript(index: Int) -> T { + assert(index >= 0 && index < count) + return internalSet[index] + } + + // Returns the 'maximum' or 'largest' value in the set. + public func max() -> T? { + return count == 0 ? nil : internalSet[count - 1] + } + + // Returns the 'minimum' or 'smallest' value in the set. + public func min() -> T? { + return count == 0 ? nil : internalSet[0] + } + + // Returns the k-th largest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kLargest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[count - k] + } + + // Returns the k-th smallest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kSmallest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[k - 1] + } +} + diff --git a/Sorted Set/SortedSet.playground/contents.xcplayground b/Sorted Set/SortedSet.playground/contents.xcplayground new file mode 100644 index 000000000..18c02c912 --- /dev/null +++ b/Sorted Set/SortedSet.playground/contents.xcplayground @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Ordered Set/OrderedSet.playground/playground.xcworkspace/contents.xcworkspacedata b/Sorted Set/SortedSet.playground/playground.xcworkspace/contents.xcworkspacedata similarity index 100% rename from Ordered Set/OrderedSet.playground/playground.xcworkspace/contents.xcworkspacedata rename to Sorted Set/SortedSet.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Sorted Set/SortedSet.swift b/Sorted Set/SortedSet.swift new file mode 100644 index 000000000..69546da0d --- /dev/null +++ b/Sorted Set/SortedSet.swift @@ -0,0 +1,118 @@ +/* + An Sorted Set is a collection where all items in the set follow an ordering, + usually sorted from 'least' to 'most'. The way you value and compare items + can be user-defined. + */ +public struct SortedSet { + private var internalSet = [T]() + + public init() { } + + // Returns the number of elements in the SortedSet. + public var count: Int { + return internalSet.count + } + + // Inserts an item. Performance: O(n) + public mutating func insert(_ item: T) { + if exists(item) { + return // don't add an item if it already exists + } + + // Insert new the item just before the one that is larger. + for i in 0.. item { + internalSet.insert(item, at: i) + return + } + } + + // Append to the back if the new item is greater than any other in the set. + internalSet.append(item) + } + + // Removes an item if it exists. Performance: O(n) + public mutating func remove(_ item: T) { + if let index = index(of: item) { + internalSet.remove(at: index) + } + } + + // Returns true if and only if the item exists somewhere in the set. + public func exists(_ item: T) -> Bool { + return index(of: item) != nil + } + + // Returns the index of an item if it exists, or -1 otherwise. + public func index(of item: T) -> Int? { + var leftBound = 0 + var rightBound = count - 1 + + while leftBound <= rightBound { + let mid = leftBound + ((rightBound - leftBound) / 2) + + if internalSet[mid] > item { + rightBound = mid - 1 + } else if internalSet[mid] < item { + leftBound = mid + 1 + } else if internalSet[mid] == item { + return mid + } else { + // When we get here, we've landed on an item whose value is equal to the + // value of the item we're looking for, but the items themselves are not + // equal. We need to check the items with the same value to the right + // and to the left in order to find an exact match. + + // Check to the right. + for j in stride(from: mid, to: count - 1, by: 1) { + if internalSet[j + 1] == item { + return j + 1 + } else if internalSet[j] < internalSet[j + 1] { + break + } + } + + // Check to the left. + for j in stride(from: mid, to: 0, by: -1) { + if internalSet[j - 1] == item { + return j - 1 + } else if internalSet[j] > internalSet[j - 1] { + break + } + } + return nil + } + } + return nil + } + + // Returns the item at the given index. + // Assertion fails if the index is out of the range of [0, count). + public subscript(index: Int) -> T { + assert(index >= 0 && index < count) + return internalSet[index] + } + + // Returns the 'maximum' or 'largest' value in the set. + public func max() -> T? { + return count == 0 ? nil : internalSet[count - 1] + } + + // Returns the 'minimum' or 'smallest' value in the set. + public func min() -> T? { + return count == 0 ? nil : internalSet[0] + } + + // Returns the k-th largest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kLargest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[count - k] + } + + // Returns the k-th smallest element in the set, if k is in the range + // [1, count]. Returns nil otherwise. + public func kSmallest(_ k: Int) -> T? { + return k > count || k <= 0 ? nil : internalSet[k - 1] + } +} + diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index fbaa4cd54..3c7134d72 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1,6 +1,19 @@ + + + + + + + + @@ -1807,12 +1820,6 @@ - - - - From c284df5882a11ad0c882ef32f32ac1e0759ff184 Mon Sep 17 00:00:00 2001 From: Emmanuoel Haroutunian Date: Wed, 22 Nov 2017 23:55:30 -0800 Subject: [PATCH 019/327] Update README code to Swift 4 --- Selection Sort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Selection Sort/README.markdown b/Selection Sort/README.markdown index cbcf5d352..b958da927 100644 --- a/Selection Sort/README.markdown +++ b/Selection Sort/README.markdown @@ -74,7 +74,7 @@ func selectionSort(_ array: [Int]) -> [Int] { } if x != lowest { // 5 - swap(&a[x], &a[lowest]) + a.swapAt(x, lowest) } } return a From ec6d34dd662eb42857d3d82197f358d4b7e64fb3 Mon Sep 17 00:00:00 2001 From: yoshi-kou Date: Sun, 26 Nov 2017 00:33:57 +0900 Subject: [PATCH 020/327] Fixed LinkedList as follows: * Modified node(atIndex:) method not to return nil, and code refactoring. * Deleted nodesBeforeAndAfter(index:) method, and modified insert methods. --- .../LinkedList.playground/Contents.swift | 169 +++++++++--------- Linked List/LinkedList.swift | 118 ++++++------ Linked List/Tests/LinkedListTests.swift | 59 +++--- 3 files changed, 166 insertions(+), 180 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index b78ee4809..559e652bb 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -42,45 +42,50 @@ public final class LinkedList { /// Computed property to iterate through the linked list and return the last node in the list (if any) public var last: Node? { - if var node = head { - while case let next? = node.next { - node = next - } - return node - } else { + guard let head = head else { return nil } + var node = head + while let next = node.next { + node = next + } + return node } /// Computed property to iterate through the linked list and return the total number of nodes public var count: Int { - if var node = head { - var c = 1 - while case let next? = node.next { - node = next - c += 1 - } - return c - } else { + guard let head = head else { return 0 } + var node = head + var count = 1 + while let next = node.next { + node = next + count += 1 + } + return count } /// Function to return the node at a specific index. Crashes if index is out of bounds (0...self.count) /// /// - Parameter index: Integer value of the node's index to be returned /// - Returns: Optional LinkedListNode - public func node(atIndex index: Int) -> Node? { - if index >= 0 { - var node = head - var i = index - while node != nil { - if i == 0 { return node } - i -= 1 - node = node!.next - } + public func node(atIndex index: Int) -> Node { + assert(head != nil, "List is empty") + if index == 0 { + return head! + } else { + var node = head!.next + for _ in 1.. { /// - Parameter index: Integer value of the requested value's index public subscript(index: Int) -> T { let node = self.node(atIndex: index) - assert(node != nil) - return node!.value + return node.value } /// Append a value to the end of the list @@ -104,7 +108,7 @@ public final class LinkedList { /// /// - Parameter node: The node containing the value to be appended public func append(_ node: Node) { - let newNode = LinkedListNode(value: node.value) + let newNode = node if let lastNode = last { newNode.previous = lastNode lastNode.next = newNode @@ -124,27 +128,6 @@ public final class LinkedList { } } - /// A private helper funciton to find the nodes before and after a specified index. Crashes if index is out of bounds (0...self.count) - /// - /// - Parameter index: Integer value of the index between the nodes. - /// - Returns: A tuple of 2 nodes before & after the specified index respectively. - private func nodesBeforeAndAfter(index: Int) -> (Node?, Node?) { - assert(index >= 0) - - var i = index - var next = head - var prev: Node? - - while next != nil && i > 0 { - i -= 1 - prev = next - next = next!.next - } - assert(i == 0) // if > 0, then specified index was too large - - return (prev, next) - } - /// Insert a value at a specific index. Crashes if index is out of bounds (0...self.count) /// /// - Parameters: @@ -161,18 +144,20 @@ public final class LinkedList { /// - node: The node containing the value to be inserted /// - index: Integer value of the index to be inserted at public func insert(_ node: Node, atIndex index: Int) { - let (prev, next) = nodesBeforeAndAfter(index: index) let newNode = LinkedListNode(value: node.value) - newNode.previous = prev - newNode.next = next - prev?.next = newNode - next?.previous = newNode - - if prev == nil { + if index == 0 { + newNode.next = head + head?.previous = newNode head = newNode + } else { + let separator = self.node(atIndex: index-1) + newNode.previous = separator + newNode.next = separator.next + separator.next?.previous = newNode + separator.next = newNode } } - + /// Insert a copy of a LinkedList at a specific index. Crashes if index is out of bounds (0...self.count) /// /// - Parameters: @@ -180,22 +165,21 @@ public final class LinkedList { /// - index: Integer value of the index to be inserted at public func insert(_ list: LinkedList, atIndex index: Int) { if list.isEmpty { return } - var (prev, next) = nodesBeforeAndAfter(index: index) - var nodeToCopy = list.head - var newNode: Node? - while let node = nodeToCopy { - newNode = Node(value: node.value) - newNode?.previous = prev - if let previous = prev { - previous.next = newNode - } else { - self.head = newNode - } - nodeToCopy = nodeToCopy?.next - prev = newNode + + if index == 0 { + let temp = head + head = list.head + list.last?.next = temp + } else { + let separate = self.node(atIndex: index-1) + let temp = separate.next + + separate.next = list.head + list.head?.previous = separate + + list.last?.next = temp + temp?.previous = list.last?.next } - prev?.next = next - next?.previous = prev } /// Function to remove all nodes/value from the list @@ -237,8 +221,7 @@ public final class LinkedList { /// - Returns: The data value contained in the deleted node @discardableResult public func remove(atIndex index: Int) -> T { let node = self.node(atIndex: index) - assert(node != nil) - return remove(node: node!) + return remove(node: node) } } @@ -324,7 +307,7 @@ list.first // nil list.last // nil list.append("Hello") -list.isEmpty +list.isEmpty // false list.first!.value // "Hello" list.last!.value // "Hello" list.count // 1 @@ -339,9 +322,9 @@ list.first!.next!.value // "World" list.last!.previous!.value // "Hello" list.last!.next // nil -list.node(atIndex: 0)!.value // "Hello" -list.node(atIndex: 1)!.value // "World" -list.node(atIndex: 2) // nil +list.node(atIndex: 0).value // "Hello" +list.node(atIndex: 1).value // "World" +//list.node(atIndex: 2) // crash! list[0] // "Hello" list[1] // "World" @@ -364,11 +347,11 @@ print(list) list.reverse() // [World, Swift, Hello] -list.node(atIndex: 0)!.value = "Universe" -list.node(atIndex: 1)!.value = "Swifty" -let m = list.map { s in s.characters.count } +list.node(atIndex: 0).value = "Universe" +list.node(atIndex: 1).value = "Swifty" +let m = list.map { s in s.count } m // [8, 6, 5] -let f = list.filter { s in s.characters.count > 5 } +let f = list.filter { s in s.count > 5 } f // [Universe, Swifty] list.remove(node: list.first!) // "Universe" @@ -376,13 +359,37 @@ list.count // 2 list[0] // "Swifty" list[1] // "Hello" +list.count // 2 list.removeLast() // "Hello" +list.head?.value list.count // 1 list[0] // "Swifty" list.remove(atIndex: 0) // "Swifty" list.count // 0 +let list3 = LinkedList() +list3.insert("2", atIndex: 0) // [2] +list3.count // 1 +list3.insert("4", atIndex: 1) // [2,4] +list3.count // 2 +list3.insert("5", atIndex: 2) // [2,4,5] +list3.count // 3 +list3.insert("3", atIndex: 1) // [2,3,4,5] +list3.insert("1", atIndex: 0) // [1,2,3,4,5] + +let list4 = LinkedList() +list4.insert(list3, atIndex: 0) // [1,2,3,4,5] +list4.count // 5 + +let list5 = LinkedList() +list5.append("0") // [0] +list5.insert("End", atIndex:1) // [0,End] +list5.count // 2 +list5.insert(list4, atIndex: 1) // [0,1,2,3,4,5,End] +list5.count // 7 + + let linkedList: LinkedList = [1, 2, 3, 4] // [1, 2, 3, 4] linkedList.count // 4 linkedList[0] // 1 diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index a5594eb31..cef6670de 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -36,35 +36,40 @@ public final class LinkedList { } public var count: Int { - if var node = head { - var c = 1 - while let next = node.next { - node = next - c += 1 - } - return c - } else { + guard let head = head else { return 0 } - } - - public func node(atIndex index: Int) -> Node? { - if index >= 0 { - var node = head - var i = index - while node != nil { - if i == 0 { return node } - i -= 1 - node = node!.next + var node = head + var count = 1 + while let next = node.next { + node = next + count += 1 + } + return count + } + + public func node(atIndex index: Int) -> Node { + assert(head != nil, "List is empty") + assert(index >= 0, "index must be greater than 0") + if index == 0 { + return head! + } else { + var node = head!.next + for _ in 1.. T { let node = self.node(atIndex: index) - assert(node != nil) - return node!.value + return node.value } public func append(_ value: T) { @@ -73,7 +78,7 @@ public final class LinkedList { } public func append(_ node: Node) { - let newNode = LinkedListNode(value: node.value) + let newNode = node if let lastNode = last { newNode.previous = lastNode lastNode.next = newNode @@ -90,61 +95,45 @@ public final class LinkedList { } } - private func nodesBeforeAndAfter(index: Int) -> (Node?, Node?) { - assert(index >= 0) - - var i = index - var next = head - var prev: Node? - - while next != nil && i > 0 { - i -= 1 - prev = next - next = next!.next - } - assert(i == 0) // if > 0, then specified index was too large - - return (prev, next) - } - public func insert(_ value: T, atIndex index: Int) { let newNode = Node(value: value) self.insert(newNode, atIndex: index) } public func insert(_ node: Node, atIndex index: Int) { - let (prev, next) = nodesBeforeAndAfter(index: index) let newNode = LinkedListNode(value: node.value) - newNode.previous = prev - newNode.next = next - prev?.next = newNode - next?.previous = newNode - - if prev == nil { + if index == 0 { + newNode.next = head + head?.previous = newNode head = newNode + } else { + let separator = self.node(atIndex: index-1) + newNode.previous = separator + newNode.next = separator.next + separator.next?.previous = newNode + separator.next = newNode } } - + public func insert(_ list: LinkedList, atIndex index: Int) { if list.isEmpty { return } - var (prev, next) = nodesBeforeAndAfter(index: index) - var nodeToCopy = list.head - var newNode: Node? - while let node = nodeToCopy { - newNode = Node(value: node.value) - newNode?.previous = prev - if let previous = prev { - previous.next = newNode - } else { - self.head = newNode - } - nodeToCopy = nodeToCopy?.next - prev = newNode + + if index == 0 { + let temp = head + head = list.head + list.last?.next = temp + } else { + let separate = self.node(atIndex: index-1) + let temp = separate.next + + separate.next = list.head + list.head?.previous = separate + + list.last?.next = temp + temp?.previous = list.last?.next } - prev?.next = next - next?.previous = prev } - + public func removeAll() { head = nil } @@ -172,8 +161,7 @@ public final class LinkedList { @discardableResult public func remove(atIndex index: Int) -> T { let node = self.node(atIndex: index) - assert(node != nil) - return remove(node: node!) + return remove(node: node) } } diff --git a/Linked List/Tests/LinkedListTests.swift b/Linked List/Tests/LinkedListTests.swift index 0b2b116df..5bc27b23d 100755 --- a/Linked List/Tests/LinkedListTests.swift +++ b/Linked List/Tests/LinkedListTests.swift @@ -93,19 +93,13 @@ class LinkedListTest: XCTestCase { XCTAssertNil(list.last!.next) } - func testNodeAtIndexInEmptyList() { - let list = LinkedList() - let node = list.node(atIndex: 0) - XCTAssertNil(node) - } - func testNodeAtIndexInListWithOneElement() { let list = LinkedList() list.append(123) let node = list.node(atIndex: 0) XCTAssertNotNil(node) - XCTAssertEqual(node!.value, 123) + XCTAssertEqual(node.value, 123) XCTAssertTrue(node === list.first) } @@ -115,23 +109,20 @@ class LinkedListTest: XCTestCase { let nodeCount = list.count XCTAssertEqual(nodeCount, numbers.count) - XCTAssertNil(list.node(atIndex: -1)) - XCTAssertNil(list.node(atIndex: nodeCount)) - let first = list.node(atIndex: 0) XCTAssertNotNil(first) XCTAssertTrue(first === list.first) - XCTAssertEqual(first!.value, numbers[0]) + XCTAssertEqual(first.value, numbers[0]) let last = list.node(atIndex: nodeCount - 1) XCTAssertNotNil(last) XCTAssertTrue(last === list.last) - XCTAssertEqual(last!.value, numbers[nodeCount - 1]) + XCTAssertEqual(last.value, numbers[nodeCount - 1]) for i in 0.. Date: Sun, 26 Nov 2017 11:39:40 +0900 Subject: [PATCH 021/327] Modified last and count method after review. --- Linked List/LinkedList.playground/Contents.swift | 8 ++++---- Linked List/LinkedList.swift | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 559e652bb..167e55b56 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -42,10 +42,10 @@ public final class LinkedList { /// Computed property to iterate through the linked list and return the last node in the list (if any) public var last: Node? { - guard let head = head else { + guard var node = head else { return nil } - var node = head + while let next = node.next { node = next } @@ -54,10 +54,10 @@ public final class LinkedList { /// Computed property to iterate through the linked list and return the total number of nodes public var count: Int { - guard let head = head else { + guard var node = head else { return 0 } - var node = head + var count = 1 while let next = node.next { node = next diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index cef6670de..e29bee86b 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -25,21 +25,21 @@ public final class LinkedList { } public var last: Node? { - if var node = head { - while let next = node.next { - node = next - } - return node - } else { + guard var node = head else { return nil } + + while let next = node.next { + node = next + } + return node } public var count: Int { - guard let head = head else { + guard var node = head else { return 0 } - var node = head + var count = 1 while let next = node.next { node = next From 71ae5a3bfb18cba13314593cad2a5da8d0906873 Mon Sep 17 00:00:00 2001 From: yoshi-kou Date: Sun, 26 Nov 2017 11:57:13 +0900 Subject: [PATCH 022/327] Renamed variables in insert methods and code refactoring. --- .../LinkedList.playground/Contents.swift | 20 +++++++++---------- Linked List/LinkedList.swift | 20 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 167e55b56..f8216fc6f 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -144,17 +144,17 @@ public final class LinkedList { /// - node: The node containing the value to be inserted /// - index: Integer value of the index to be inserted at public func insert(_ node: Node, atIndex index: Int) { - let newNode = LinkedListNode(value: node.value) + let newNode = node if index == 0 { newNode.next = head head?.previous = newNode head = newNode } else { - let separator = self.node(atIndex: index-1) - newNode.previous = separator - newNode.next = separator.next - separator.next?.previous = newNode - separator.next = newNode + let prev = self.node(atIndex: index-1) + newNode.previous = prev + newNode.next = prev.next + prev.next?.previous = newNode + prev.next = newNode } } @@ -171,11 +171,11 @@ public final class LinkedList { head = list.head list.last?.next = temp } else { - let separate = self.node(atIndex: index-1) - let temp = separate.next + let prev = self.node(atIndex: index-1) + let temp = prev.next - separate.next = list.head - list.head?.previous = separate + prev.next = list.head + list.head?.previous = prev list.last?.next = temp temp?.previous = list.last?.next diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index e29bee86b..c0331bc0e 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -101,17 +101,17 @@ public final class LinkedList { } public func insert(_ node: Node, atIndex index: Int) { - let newNode = LinkedListNode(value: node.value) + let newNode = node if index == 0 { newNode.next = head head?.previous = newNode head = newNode } else { - let separator = self.node(atIndex: index-1) - newNode.previous = separator - newNode.next = separator.next - separator.next?.previous = newNode - separator.next = newNode + let prev = self.node(atIndex: index-1) + newNode.previous = prev + newNode.next = prev.next + prev.next?.previous = newNode + prev.next = newNode } } @@ -123,11 +123,11 @@ public final class LinkedList { head = list.head list.last?.next = temp } else { - let separate = self.node(atIndex: index-1) - let temp = separate.next + let prev = self.node(atIndex: index-1) + let temp = prev.next - separate.next = list.head - list.head?.previous = separate + prev.next = list.head + list.head?.previous = prev list.last?.next = temp temp?.previous = list.last?.next From bd7e4b1ef7a3d0c787aa74e06bc54750cf140805 Mon Sep 17 00:00:00 2001 From: yoshi-kou Date: Sun, 26 Nov 2017 12:09:43 +0900 Subject: [PATCH 023/327] Fixed node(atIndex:) method to be the same in LinkedList.swift file. --- Linked List/LinkedList.playground/Contents.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index f8216fc6f..af27f63a0 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -72,6 +72,8 @@ public final class LinkedList { /// - Returns: Optional LinkedListNode public func node(atIndex index: Int) -> Node { assert(head != nil, "List is empty") + assert(index >= 0, "index must be greater than 0") + if index == 0 { return head! } else { From b68e1fd411e8698c5de39bccb240fd6649acd3f7 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Sun, 26 Nov 2017 12:12:52 +0500 Subject: [PATCH 024/327] Fix a few typos in QuadTree/README.md Quadrees -> Quadtrees containts -> contains Wiki -> Wikipedia Also my editor automatically removed trailing spaces from empty lines --- QuadTree/README.md | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/QuadTree/README.md b/QuadTree/README.md index ff71a66f0..ff660f852 100644 --- a/QuadTree/README.md +++ b/QuadTree/README.md @@ -6,11 +6,11 @@ A quadtree is a [tree](https://github.com/raywenderlich/swift-algorithm-club/tre ### Problem -Consider the following problem: your need to store a number of points (each point is a pair of `X` and `Y` coordinates) and then you need to answer which points lie in a certain rectangular region. A naive solution would be to store the points inside an array and then iterate over the points and check each one individually. This solution runs in O(n) though. +Consider the following problem: your need to store a number of points (each point is a pair of `X` and `Y` coordinates) and then you need to answer which points lie in a certain rectangular region. A naive solution would be to store the points inside an array and then iterate over the points and check each one individually. This solution runs in O(n) though. ### A Better Approach -Quadrees are most commonly used to partition a two-dimensional space by recursively subdividing it into four regions(quadrants). Let's see how we can use a Quadtree to store the points. +Quadtrees are most commonly used to partition a two-dimensional space by recursively subdividing it into four regions(quadrants). Let's see how we can use a Quadtree to store the points. Each node in the tree represents a rectangular region and stores a limited number(`maxPointCapacity`) of points that all lie in its region. @@ -40,7 +40,7 @@ class QuadTreeNode { init(rect: Rect) { self.rect = rect } - + ... } @@ -52,11 +52,11 @@ extension QuadTreeNode { @discardableResult func add(point: Point) -> Bool { - - if !rect.containts(point: point) { + + if !rect.contains(point: point) { return false } - + switch type { case .internal(let children): // pass the point to one of the children @@ -75,7 +75,7 @@ extension QuadTreeNode { } return true } - + private func subdivide() { switch type { case .leaf: @@ -105,9 +105,9 @@ To find the points that lie in a given region we can now traverse the tree from class QuadTree { ... - + let root: QuadTreeNode - + public func points(inRect rect: Rect) -> [Point] { return root.points(inRect: rect) } @@ -115,23 +115,23 @@ class QuadTree { extension QuadTreeNode { func points(inRect rect: Rect) -> [Point] { - + // if the node's rect and the given rect don't intersect, return an empty array, // because there can't be any points that lie the node's (or its children's) rect and // in the given rect if !self.rect.intersects(rect: rect) { return [] } - + var result: [Point] = [] - + // collect the node's points that lie in the rect for point in points { - if rect.containts(point: point) { + if rect.contains(point: point) { result.append(point) } } - + switch type { case .leaf: break @@ -141,7 +141,7 @@ extension QuadTreeNode { result.append(contentsOf: childNode.points(inRect: rect)) } } - + return result } } @@ -154,7 +154,6 @@ Both adding a point and searching can still take up to O(n) in the worst case, s Displaying a large amount of objects in a MapView - a great use case for a Quadtree ([Thoughtbot Article](https://robots.thoughtbot.com/how-to-handle-large-amounts-of-data-on-maps)) -More info on [Wiki](https://en.wikipedia.org/wiki/Quadtree) +More info on [Wikipedia](https://en.wikipedia.org/wiki/Quadtree) *Written for Swift Algorithm Club by Timur Galimov* - From fcf235ce42ae0bc281e78b48a79fa6e5174b2109 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Sun, 26 Nov 2017 12:27:27 +0500 Subject: [PATCH 025/327] Fix typos alogrithm -> algorithm collison -> collison Also added a "to" to improved grammar and added newline to the file --- Rabin-Karp/README.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Rabin-Karp/README.markdown b/Rabin-Karp/README.markdown index 79699caa8..4470c7f75 100644 --- a/Rabin-Karp/README.markdown +++ b/Rabin-Karp/README.markdown @@ -1,6 +1,6 @@ # Rabin-Karp string search algorithm -The Rabin-Karp string search alogrithm is used to search text for a pattern. +The Rabin-Karp string search algorithm is used to search text for a pattern. A practical application of the algorithm is detecting plagiarism. Given source material, the algorithm can rapidly search through a paper for instances of sentences from the source material, ignoring details such as case and punctuation. Because of the abundance of the sought strings, single-string searching algorithms are impractical. @@ -12,10 +12,10 @@ at a time (e.g. "he ") and subtracts out the previous hash from the "T". ## Algorithm -The Rabin-Karp alogrithm uses a sliding window the size of the search pattern. It starts by hashing the search pattern, then +The Rabin-Karp algorithm uses a sliding window the size of the search pattern. It starts by hashing the search pattern, then hashing the first x characters of the text string where x is the length of the search pattern. It then slides the window one character over and uses the previous hash value to calculate the new hash faster. Only when it finds a hash that matches the hash of the search pattern will it compare -the two strings it see if they are the same (prevent a hash collision from producing a false positive) +the two strings it see if they are the same (to prevent a hash collision from producing a false positive). ## The code @@ -37,7 +37,7 @@ public func search(text: String , pattern: String) -> Int { let firstHash = hash(array: firstChars) if (patternHash == firstHash) { - // Verify this was not a hash collison + // Verify this was not a hash collision if firstChars == patternArray { return 0 } @@ -76,4 +76,4 @@ This will return 13 since ump is in the 13 position of the zero based string. [Rabin-Karp Wikipedia](https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm) -*Written by [Bill Barbour](https://github.com/brbatwork)* \ No newline at end of file +*Written by [Bill Barbour](https://github.com/brbatwork)* From 7e75d1086ee7c0dbac5ee2096eb294ef14c30324 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Sun, 26 Nov 2017 12:27:47 +0500 Subject: [PATCH 026/327] Fix warning: 'characters' is deprecated: Please use String or Substring directly --- Rabin-Karp/README.markdown | 4 ++-- Rabin-Karp/Rabin-Karp.playground/Contents.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Rabin-Karp/README.markdown b/Rabin-Karp/README.markdown index 4470c7f75..a618d3981 100644 --- a/Rabin-Karp/README.markdown +++ b/Rabin-Karp/README.markdown @@ -24,8 +24,8 @@ The major search method is next. More implementation details are in rabin-karp. ```swift public func search(text: String , pattern: String) -> Int { // convert to array of ints - let patternArray = pattern.characters.flatMap { $0.asInt } - let textArray = text.characters.flatMap { $0.asInt } + let patternArray = pattern.flatMap { $0.asInt } + let textArray = text.flatMap { $0.asInt } if textArray.count < patternArray.count { return -1 diff --git a/Rabin-Karp/Rabin-Karp.playground/Contents.swift b/Rabin-Karp/Rabin-Karp.playground/Contents.swift index c0a99339a..739b74e2a 100644 --- a/Rabin-Karp/Rabin-Karp.playground/Contents.swift +++ b/Rabin-Karp/Rabin-Karp.playground/Contents.swift @@ -30,8 +30,8 @@ extension Character { // Find first position of pattern in the text using Rabin Karp algorithm public func search(text: String, pattern: String) -> Int { // convert to array of ints - let patternArray = pattern.characters.flatMap { $0.asInt } - let textArray = text.characters.flatMap { $0.asInt } + let patternArray = pattern.flatMap { $0.asInt } + let textArray = text.flatMap { $0.asInt } if textArray.count < patternArray.count { return -1 From 885d9d3d650296e15fa8b12eba734c36afb9069a Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Sun, 26 Nov 2017 12:48:57 +0500 Subject: [PATCH 027/327] Fix warning: Result of call to 'addNode' is unused --- .../DepthFirstSearch.playground/Sources/Graph.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift b/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift index 34ee2fa3a..48b8feed5 100644 --- a/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift +++ b/Depth-First Search/DepthFirstSearch.playground/Sources/Graph.swift @@ -5,6 +5,7 @@ public class Graph: CustomStringConvertible, Equatable { self.nodes = [] } + @discardableResult public func addNode(_ label: String) -> Node { let node = Node(label) nodes.append(node) From 0b129e8894ec9699f5ebee60c2bcddddc256b770 Mon Sep 17 00:00:00 2001 From: yoshi-kou Date: Tue, 28 Nov 2017 00:56:30 +0900 Subject: [PATCH 028/327] Modified readme file in LinkedList. --- Linked List/README.markdown | 227 ++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 103 deletions(-) diff --git a/Linked List/README.markdown b/Linked List/README.markdown index 2e1f03ece..55b61e910 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -110,14 +110,14 @@ Let's also add a property that gives you the last node in the list. This is wher ```swift public var last: Node? { - if var node = head { - while let next = node.next { - node = next - } - return node - } else { + guard var node = head else { return nil } + + while let next = node.next { + node = next + } + return node } ``` @@ -198,16 +198,16 @@ Let's add a method to count how many nodes are in the list. This will look very ```swift public var count: Int { - if var node = head { - var c = 1 - while let next = node.next { - node = next - c += 1 - } - return c - } else { + guard var node = head else { return 0 } + + var count = 1 + while let next = node.next { + node = next + count += 1 + } + return count } ``` @@ -218,37 +218,43 @@ It loops through the list in the same manner but this time increments a counter What if we wanted to find the node at a specific index in the list? With an array we can just write `array[index]` and it's an **O(1)** operation. It's a bit more involved with linked lists, but again the code follows a similar pattern: ```swift - public func nodeAt(_ index: Int) -> Node? { - if index >= 0 { - var node = head - var i = index - while node != nil { - if i == 0 { return node } - i -= 1 - node = node!.next + public func node(atIndex index: Int) -> Node { + if index == 0 { + return head! + } else { + var node = head!.next + for _ in 1.. T { - let node = nodeAt(index) - assert(node != nil) - return node!.value + let node = node(atIndex: index) + return node.value } ``` @@ -264,84 +270,100 @@ It crashes on `list[2]` because there is no node at that index. So far we've written code to add new nodes to the end of the list, but that's slow because you need to find the end of the list first. (It would be fast if we used a tail pointer.) For this reason, if the order of the items in the list doesn't matter, you should insert at the front of the list instead. That's always an **O(1)** operation. -Let's write a method that lets you insert a new node at any index in the list. First, we'll define a helper function: - -```swift - private func nodesBeforeAndAfter(index: Int) -> (Node?, Node?) { - assert(index >= 0) - - var i = index - var next = head - var prev: Node? - - while next != nil && i > 0 { - i -= 1 - prev = next - next = next!.next - } - assert(i == 0) - - return (prev, next) - } -``` - -This returns a tuple containing the node currently at the specified index and the node that immediately precedes it, if any. The loop is very similar to `nodeAtIndex()`, except that here we also keep track of what the previous node is as we iterate through the list. - -Let's look at an example. Suppose we have the following list: - head --> A --> B --> C --> D --> E --> nil - -We want to find the nodes before and after index 3. As we start the loop, `i = 3`, `next` points at `"A"`, and `prev` is nil. - - head --> A --> B --> C --> D --> E --> nil - next - -We decrement `i`, make `prev` point to `"A"`, and move `next` to the next node, `"B"`: - - head --> A --> B --> C --> D --> E --> F --> nil - prev next - -Again, we decrement `i` and update the pointers. Now `prev` points to `"B"`, and `next` points to `"C"`: - - head --> A --> B --> C --> D --> E --> F --> nil - prev next - -As you can see, `prev` always follows one behind `next`. We do this one more time and then `i` equals 0 and we exit the loop: - - head --> A --> B --> C --> D --> E --> F --> nil - prev next - -The `assert()` after the loop checks whether there really were enough nodes in the list. If `i > 0` at this point, then the specified index was too large. - -> **Note:** If any of the loops in this article don't make much sense to you, then draw a linked list on a piece of paper and step through the loop by hand, just like what we did here. - -For this example, the function returns `("C", "D")` because `"D"` is the node at index 3 and `"C"` is the one right before that. - -Now that we have this helper function, we can write the method for inserting nodes: +Let's write a method that lets you insert a new node at any index in the list. ```swift - public func insert(value: T, atIndex index: Int) { - let (prev, next) = nodesBeforeAndAfter(index) // 1 - - let newNode = Node(value: value) // 2 - newNode.previous = prev - newNode.next = next - prev?.next = newNode - next?.previous = newNode - - if prev == nil { // 3 - head = newNode - } - } + public func insert(_ node: Node, atIndex index: Int) { + let newNode = node + if index == 0 { + newNode.next = head + head?.previous = newNode + head = newNode + } else { + let prev = self.node(atIndex: index-1) + let next = prev.next + + newNode.previous = prev + newNode.next = prev.next + prev.next = newNode + next?.previous = newNode + } +} ``` -Some remarks about this method: - -1. First, we need to find where to insert this node. After calling the helper method, `prev` points to the previous node and `next` is the node currently at the given index. We'll insert the new node in between these two. Note that `prev` can be nil (index is 0), `next` can be nil (index equals size of the list), or both can be nil if the list is empty. +As with node(atIndex :) method, insert(_: at:) method also branches depending on whether the given index is 0 or not. +First let's look at the former case. Suppose we have the following list and the new node(C). + + +---------+ +---------+ + head --->| |---->| |-----//-----> + | A | | B | + nil <---| |<----| |<----//------ + +---------+ +---------+ + [0] [1] + + + +---------+ + new --->| |----> nil + | C | + | | + +---------+ + +Now put the new node before the first node. In this way: + + new.next = head + head.previous = new + + +---------+ +---------+ +---------+ + new --->| |--> head -->| |---->| |-----//-----> + | C | | A | | B | + | |<-----------| |<----| |<----//------ + +---------+ +---------+ +---------+ + + +Finally, replace the head with the new node. + + head = new + + +---------+ +---------+ +---------+ + head --->| |--->| |---->| |-----//-----> + | C | | A | | B | + nil <---| |<---| |<----| |<----//------ + +---------+ +---------+ +---------+ + [0] [1] + + +However, when the given index is greater than 0, it is necessary to get the node previous and next index and insert between them. +You can also obtain the previous and next node using node(atIndex:) as follows: + + +---------+ +---------+ +---------+ + head --->| |---//--->| |---->| |---- + | 0 | | A | | B | + nil <---| |---//<---| |<----| |<--- + +---------+ +---------+ +---------+ + [index-1] [index] + ^ ^ + | | + prev next + + prev = node(at: index-1) + next = prev.next + +Now insert new node between the prev and the next. + + new.prev = prev; prev.next = new // connect prev and new. + new.next = next; next.prev = new // connect new and next. + + +---------+ +---------+ +---------+ +---------+ + head --->| |---//--->| |---->| |---->| | + | 0 | | A | | C | | B | + nil <---| |---//<---| |<----| |<----| | + +---------+ +---------+ +---------+ +---------+ + [index-1] [index] [index+1] + ^ ^ ^ + | | | + prev new next -2. Create the new node and connect the `previous` and `next` pointers. Because the local `prev` and `next` variables are optionals and may be nil, so we use optional chaining here. - -3. If the new node is being inserted at the front of the list, we need to update the `head` pointer. (Note: If the list had a tail pointer, you'd also need to update that pointer here if `next == nil`, because that means the last element has changed.) Try it out: @@ -353,8 +375,7 @@ list[2] // "World" ``` Also try adding new nodes to the front and back of the list, to verify that this works properly. - -> **Note:** The `nodesBeforeAndAfter()` and `insert(atIndex)` functions can also be used with a singly linked list because we don't depend on the node's `previous` pointer to find the previous element. +> **Note:** The `node(atIndex:)` and `insert(_: atIndex:)` functions can also be used with a singly linked list because we don't depend on the node's `previous` pointer to find the previous element. What else do we need? Removing nodes, of course! First we'll do `removeAll()`, which is really simple: @@ -515,7 +536,7 @@ And here's filter: And a silly example: ```swift -let f = list.filter { s in s.characters.count > 5 } +let f = list.filter { s in s.count > 5 } f // [Universe, Swifty] ``` From 3de5a1bfc49f9019badd6ba32fa23b0452e30d71 Mon Sep 17 00:00:00 2001 From: yoshi-kou Date: Wed, 29 Nov 2017 13:12:47 +0900 Subject: [PATCH 029/327] Fixed insert method and some related files. --- .../LinkedList.playground/Contents.swift | 21 +++++++++---------- Linked List/LinkedList.swift | 19 ++++++++--------- Linked List/README.markdown | 10 ++++----- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index af27f63a0..2b7d2873b 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -145,17 +145,17 @@ public final class LinkedList { /// - Parameters: /// - node: The node containing the value to be inserted /// - index: Integer value of the index to be inserted at - public func insert(_ node: Node, atIndex index: Int) { - let newNode = node + public func insert(_ newNode: Node, atIndex index: Int) { if index == 0 { newNode.next = head head?.previous = newNode head = newNode } else { - let prev = self.node(atIndex: index-1) + let prev = node(atIndex: index-1) + let next = prev.next newNode.previous = prev - newNode.next = prev.next - prev.next?.previous = newNode + newNode.next = next + next?.previous = newNode prev.next = newNode } } @@ -169,18 +169,17 @@ public final class LinkedList { if list.isEmpty { return } if index == 0 { - let temp = head + list.last?.next = head head = list.head - list.last?.next = temp } else { - let prev = self.node(atIndex: index-1) - let temp = prev.next + let prev = node(atIndex: index-1) + let next = prev.next prev.next = list.head list.head?.previous = prev - list.last?.next = temp - temp?.previous = list.last?.next + list.last?.next = next + next?.previous = list.last?.next } } diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index c0331bc0e..a9848328d 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -100,17 +100,17 @@ public final class LinkedList { self.insert(newNode, atIndex: index) } - public func insert(_ node: Node, atIndex index: Int) { - let newNode = node + public func insert(_ newNode: Node, atIndex index: Int) { if index == 0 { newNode.next = head head?.previous = newNode head = newNode } else { - let prev = self.node(atIndex: index-1) + let prev = node(atIndex: index-1) + let next = prev.next newNode.previous = prev - newNode.next = prev.next - prev.next?.previous = newNode + newNode.next = next + next?.previous = newNode prev.next = newNode } } @@ -119,18 +119,17 @@ public final class LinkedList { if list.isEmpty { return } if index == 0 { - let temp = head + list.last?.next = head head = list.head - list.last?.next = temp } else { let prev = self.node(atIndex: index-1) - let temp = prev.next + let next = prev.next prev.next = list.head list.head?.previous = prev - list.last?.next = temp - temp?.previous = list.last?.next + list.last?.next = next + next?.previous = list.last?.next } } diff --git a/Linked List/README.markdown b/Linked List/README.markdown index 55b61e910..52e30261a 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -330,7 +330,7 @@ Finally, replace the head with the new node. | C | | A | | B | nil <---| |<---| |<----| |<----//------ +---------+ +---------+ +---------+ - [0] [1] + [0] [1] [2] However, when the given index is greater than 0, it is necessary to get the node previous and next index and insert between them. @@ -338,10 +338,10 @@ You can also obtain the previous and next node using node(atIndex:) as follows: +---------+ +---------+ +---------+ head --->| |---//--->| |---->| |---- - | 0 | | A | | B | + | | | A | | B | nil <---| |---//<---| |<----| |<--- +---------+ +---------+ +---------+ - [index-1] [index] + [0] [index-1] [index] ^ ^ | | prev next @@ -356,10 +356,10 @@ Now insert new node between the prev and the next. +---------+ +---------+ +---------+ +---------+ head --->| |---//--->| |---->| |---->| | - | 0 | | A | | C | | B | + | | | A | | C | | B | nil <---| |---//<---| |<----| |<----| | +---------+ +---------+ +---------+ +---------+ - [index-1] [index] [index+1] + [0] [index-1] [index] [index+1] ^ ^ ^ | | | prev new next From bb21f61b53dc08af0e5d5081951c683d0f57a979 Mon Sep 17 00:00:00 2001 From: yoshi-kou Date: Thu, 30 Nov 2017 15:40:48 +0900 Subject: [PATCH 030/327] [Code refactoring] Renamed `atIndex` label in method to `at`. --- .../LinkedList.playground/Contents.swift | 52 +++++++------- Linked List/LinkedList.swift | 20 +++--- Linked List/Tests/LinkedListTests.swift | 68 +++++++++---------- 3 files changed, 70 insertions(+), 70 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 2b7d2873b..b215bb3c7 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -70,7 +70,7 @@ public final class LinkedList { /// /// - Parameter index: Integer value of the node's index to be returned /// - Returns: Optional LinkedListNode - public func node(atIndex index: Int) -> Node { + public func node(at index: Int) -> Node { assert(head != nil, "List is empty") assert(index >= 0, "index must be greater than 0") @@ -94,7 +94,7 @@ public final class LinkedList { /// /// - Parameter index: Integer value of the requested value's index public subscript(index: Int) -> T { - let node = self.node(atIndex: index) + let node = self.node(at: index) return node.value } @@ -135,9 +135,9 @@ public final class LinkedList { /// - Parameters: /// - value: The data value to be inserted /// - index: Integer value of the index to be insterted at - public func insert(_ value: T, atIndex index: Int) { + public func insert(_ value: T, at index: Int) { let newNode = Node(value: value) - self.insert(newNode, atIndex: index) + self.insert(newNode, at: index) } /// Insert a copy of a node at a specific index. Crashes if index is out of bounds (0...self.count) @@ -145,13 +145,13 @@ public final class LinkedList { /// - Parameters: /// - node: The node containing the value to be inserted /// - index: Integer value of the index to be inserted at - public func insert(_ newNode: Node, atIndex index: Int) { + public func insert(_ newNode: Node, at index: Int) { if index == 0 { newNode.next = head head?.previous = newNode head = newNode } else { - let prev = node(atIndex: index-1) + let prev = node(at: index-1) let next = prev.next newNode.previous = prev newNode.next = next @@ -165,14 +165,14 @@ public final class LinkedList { /// - Parameters: /// - list: The LinkedList to be copied and inserted /// - index: Integer value of the index to be inserted at - public func insert(_ list: LinkedList, atIndex index: Int) { + public func insert(_ list: LinkedList, at index: Int) { if list.isEmpty { return } if index == 0 { list.last?.next = head head = list.head } else { - let prev = node(atIndex: index-1) + let prev = node(at: index-1) let next = prev.next prev.next = list.head @@ -220,8 +220,8 @@ public final class LinkedList { /// /// - Parameter index: Integer value of the index of the node to be removed /// - Returns: The data value contained in the deleted node - @discardableResult public func remove(atIndex index: Int) -> T { - let node = self.node(atIndex: index) + @discardableResult public func remove(at index: Int) -> T { + let node = self.node(at: index) return remove(node: node) } } @@ -323,9 +323,9 @@ list.first!.next!.value // "World" list.last!.previous!.value // "Hello" list.last!.next // nil -list.node(atIndex: 0).value // "Hello" -list.node(atIndex: 1).value // "World" -//list.node(atIndex: 2) // crash! +list.node(at: 0).value // "Hello" +list.node(at: 1).value // "World" +//list.node(at: 2) // crash! list[0] // "Hello" list[1] // "World" @@ -338,9 +338,9 @@ list.append(list2) // [Hello, World, Goodbye, World] list2.removeAll() // [ ] list2.isEmpty // true list.removeLast() // "World" -list.remove(atIndex: 2) // "Goodbye" +list.remove(at: 2) // "Goodbye" -list.insert("Swift", atIndex: 1) +list.insert("Swift", at: 1) list[0] // "Hello" list[1] // "Swift" list[2] // "World" @@ -348,8 +348,8 @@ print(list) list.reverse() // [World, Swift, Hello] -list.node(atIndex: 0).value = "Universe" -list.node(atIndex: 1).value = "Swifty" +list.node(at: 0).value = "Universe" +list.node(at: 1).value = "Swifty" let m = list.map { s in s.count } m // [8, 6, 5] let f = list.filter { s in s.count > 5 } @@ -366,28 +366,28 @@ list.head?.value list.count // 1 list[0] // "Swifty" -list.remove(atIndex: 0) // "Swifty" +list.remove(at: 0) // "Swifty" list.count // 0 let list3 = LinkedList() -list3.insert("2", atIndex: 0) // [2] +list3.insert("2", at: 0) // [2] list3.count // 1 -list3.insert("4", atIndex: 1) // [2,4] +list3.insert("4", at: 1) // [2,4] list3.count // 2 -list3.insert("5", atIndex: 2) // [2,4,5] +list3.insert("5", at: 2) // [2,4,5] list3.count // 3 -list3.insert("3", atIndex: 1) // [2,3,4,5] -list3.insert("1", atIndex: 0) // [1,2,3,4,5] +list3.insert("3", at: 1) // [2,3,4,5] +list3.insert("1", at: 0) // [1,2,3,4,5] let list4 = LinkedList() -list4.insert(list3, atIndex: 0) // [1,2,3,4,5] +list4.insert(list3, at: 0) // [1,2,3,4,5] list4.count // 5 let list5 = LinkedList() list5.append("0") // [0] -list5.insert("End", atIndex:1) // [0,End] +list5.insert("End", at:1) // [0,End] list5.count // 2 -list5.insert(list4, atIndex: 1) // [0,1,2,3,4,5,End] +list5.insert(list4, at: 1) // [0,1,2,3,4,5,End] list5.count // 7 diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index a9848328d..14f2ffe29 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -48,7 +48,7 @@ public final class LinkedList { return count } - public func node(atIndex index: Int) -> Node { + public func node(at index: Int) -> Node { assert(head != nil, "List is empty") assert(index >= 0, "index must be greater than 0") if index == 0 { @@ -68,7 +68,7 @@ public final class LinkedList { } public subscript(index: Int) -> T { - let node = self.node(atIndex: index) + let node = self.node(at: index) return node.value } @@ -95,18 +95,18 @@ public final class LinkedList { } } - public func insert(_ value: T, atIndex index: Int) { + public func insert(_ value: T, at index: Int) { let newNode = Node(value: value) - self.insert(newNode, atIndex: index) + self.insert(newNode, at: index) } - public func insert(_ newNode: Node, atIndex index: Int) { + public func insert(_ newNode: Node, at index: Int) { if index == 0 { newNode.next = head head?.previous = newNode head = newNode } else { - let prev = node(atIndex: index-1) + let prev = node(at: index-1) let next = prev.next newNode.previous = prev newNode.next = next @@ -115,14 +115,14 @@ public final class LinkedList { } } - public func insert(_ list: LinkedList, atIndex index: Int) { + public func insert(_ list: LinkedList, at index: Int) { if list.isEmpty { return } if index == 0 { list.last?.next = head head = list.head } else { - let prev = self.node(atIndex: index-1) + let prev = self.node(at: index-1) let next = prev.next prev.next = list.head @@ -158,8 +158,8 @@ public final class LinkedList { return remove(node: last!) } - @discardableResult public func remove(atIndex index: Int) -> T { - let node = self.node(atIndex: index) + @discardableResult public func remove(at index: Int) -> T { + let node = self.node(at: index) return remove(node: node) } } diff --git a/Linked List/Tests/LinkedListTests.swift b/Linked List/Tests/LinkedListTests.swift index 5bc27b23d..969ee5e08 100755 --- a/Linked List/Tests/LinkedListTests.swift +++ b/Linked List/Tests/LinkedListTests.swift @@ -97,7 +97,7 @@ class LinkedListTest: XCTestCase { let list = LinkedList() list.append(123) - let node = list.node(atIndex: 0) + let node = list.node(at: 0) XCTAssertNotNil(node) XCTAssertEqual(node.value, 123) XCTAssertTrue(node === list.first) @@ -109,18 +109,18 @@ class LinkedListTest: XCTestCase { let nodeCount = list.count XCTAssertEqual(nodeCount, numbers.count) - let first = list.node(atIndex: 0) + let first = list.node(at: 0) XCTAssertNotNil(first) XCTAssertTrue(first === list.first) XCTAssertEqual(first.value, numbers[0]) - let last = list.node(atIndex: nodeCount - 1) + let last = list.node(at: nodeCount - 1) XCTAssertNotNil(last) XCTAssertTrue(last === list.last) XCTAssertEqual(last.value, numbers[nodeCount - 1]) for i in 0..() - list.insert(123, atIndex: 0) + list.insert(123, at: 0) XCTAssertFalse(list.isEmpty) XCTAssertEqual(list.count, 1) - let node = list.node(atIndex: 0) + let node = list.node(at: 0) XCTAssertNotNil(node) XCTAssertEqual(node.value, 123) } func testInsertAtIndex() { let list = buildList() - let prev = list.node(atIndex: 2) - let next = list.node(atIndex: 3) + let prev = list.node(at: 2) + let next = list.node(at: 3) let nodeCount = list.count - list.insert(444, atIndex: 3) + list.insert(444, at: 3) - let node = list.node(atIndex: 3) + let node = list.node(at: 3) XCTAssertNotNil(node) XCTAssertEqual(node.value, 444) XCTAssertEqual(nodeCount + 1, list.count) @@ -169,12 +169,12 @@ class LinkedListTest: XCTestCase { let list2 = LinkedList() list2.append(99) list2.append(102) - list.insert(list2, atIndex: 2) + list.insert(list2, at: 2) XCTAssertTrue(list.count == 8) - XCTAssertEqual(list.node(atIndex: 1).value, 2) - XCTAssertEqual(list.node(atIndex: 2).value, 99) - XCTAssertEqual(list.node(atIndex: 3).value, 102) - XCTAssertEqual(list.node(atIndex: 4).value, 10) + XCTAssertEqual(list.node(at: 1).value, 2) + XCTAssertEqual(list.node(at: 2).value, 99) + XCTAssertEqual(list.node(at: 3).value, 102) + XCTAssertEqual(list.node(at: 4).value, 10) } func testInsertListAtFirstIndex() { @@ -182,11 +182,11 @@ class LinkedListTest: XCTestCase { let list2 = LinkedList() list2.append(99) list2.append(102) - list.insert(list2, atIndex: 0) + list.insert(list2, at: 0) XCTAssertTrue(list.count == 8) - XCTAssertEqual(list.node(atIndex: 0).value, 99) - XCTAssertEqual(list.node(atIndex: 1).value, 102) - XCTAssertEqual(list.node(atIndex: 2).value, 8) + XCTAssertEqual(list.node(at: 0).value, 99) + XCTAssertEqual(list.node(at: 1).value, 102) + XCTAssertEqual(list.node(at: 2).value, 8) } func testInsertListAtLastIndex() { @@ -194,11 +194,11 @@ class LinkedListTest: XCTestCase { let list2 = LinkedList() list2.append(99) list2.append(102) - list.insert(list2, atIndex: list.count) + list.insert(list2, at: list.count) XCTAssertTrue(list.count == 8) - XCTAssertEqual(list.node(atIndex: 5).value, 5) - XCTAssertEqual(list.node(atIndex: 6).value, 99) - XCTAssertEqual(list.node(atIndex: 7).value, 102) + XCTAssertEqual(list.node(at: 5).value, 5) + XCTAssertEqual(list.node(at: 6).value, 99) + XCTAssertEqual(list.node(at: 7).value, 102) } func testAppendList() { @@ -208,9 +208,9 @@ class LinkedListTest: XCTestCase { list2.append(102) list.append(list2) XCTAssertTrue(list.count == 8) - XCTAssertEqual(list.node(atIndex: 5).value, 5) - XCTAssertEqual(list.node(atIndex: 6).value, 99) - XCTAssertEqual(list.node(atIndex: 7).value, 102) + XCTAssertEqual(list.node(at: 5).value, 5) + XCTAssertEqual(list.node(at: 6).value, 99) + XCTAssertEqual(list.node(at: 7).value, 102) } func testAppendListToEmptyList() { @@ -220,15 +220,15 @@ class LinkedListTest: XCTestCase { list2.append(10) list.append(list2) XCTAssertTrue(list.count == 2) - XCTAssertEqual(list.node(atIndex: 0).value, 5) - XCTAssertEqual(list.node(atIndex: 1).value, 10) + XCTAssertEqual(list.node(at: 0).value, 5) + XCTAssertEqual(list.node(at: 1).value, 10) } func testRemoveAtIndexOnListWithOneElement() { let list = LinkedList() list.append(123) - let value = list.remove(atIndex: 0) + let value = list.remove(at: 0) XCTAssertEqual(value, 123) XCTAssertTrue(list.isEmpty) @@ -239,16 +239,16 @@ class LinkedListTest: XCTestCase { func testRemoveAtIndex() { let list = buildList() - let prev = list.node(atIndex: 2) - let next = list.node(atIndex: 3) + let prev = list.node(at: 2) + let next = list.node(at: 3) let nodeCount = list.count - list.insert(444, atIndex: 3) + list.insert(444, at: 3) - let value = list.remove(atIndex: 3) + let value = list.remove(at: 3) XCTAssertEqual(value, 444) - let node = list.node(atIndex: 3) + let node = list.node(at: 3) XCTAssertTrue(next === node) XCTAssertTrue(prev.next === node) XCTAssertTrue(node.previous === prev) From aa6e2bf750322666722c8fdea77b2dae4476cc5b Mon Sep 17 00:00:00 2001 From: Hai Nguyen Date: Sat, 2 Dec 2017 14:43:05 -0800 Subject: [PATCH 031/327] GitHub Pages Script Updates (#670) * Move inline css to the main stylesheet - github-light.css & parse the repo README to html instead of generating one. * Minor clean up * Fix image link * Parse other markdown files --- .travis.yml | 1 + README.markdown | 8 +-- gfm-render.sh | 175 +++++++++++++++++++++++++++++------------------- 3 files changed, 110 insertions(+), 74 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7cd02c9bc..edf1cf89f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,4 +50,5 @@ script: - xcodebuild test -project ./Ternary\ Search\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` after_success: + - if [[ "$TRAVIS_BRANCH" == "master" ]]; then ./gfm-render.sh; fi diff --git a/README.markdown b/README.markdown index b15bd1527..46544682e 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,4 @@ -![Swift Algorithm Club](/Images/SwiftAlgorithm-410-transp.png) +![Swift Algorithm Club](Images/SwiftAlgorithm-410-transp.png) # Welcome to the Swift Algorithm Club! @@ -156,14 +156,14 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - [Splay Tree](Splay%20Tree/). A self balancing binary search tree that enables fast retrieval of recently updated elements. - [Threaded Binary Tree](Threaded%20Binary%20Tree/). A binary tree that maintains a few extra variables for cheap and fast in-order traversals. - [Segment Tree](Segment%20Tree/). Can quickly compute a function over a portion of an array. - - [Lazy Propagation](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Segment%20Tree/LazyPropagation) + - [Lazy Propagation](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Segment%20Tree/LazyPropagation) - kd-Tree - [Heap](Heap/). A binary tree stored in an array, so it doesn't use pointers. Makes a great priority queue. - Fibonacci Heap - [Trie](Trie/). A special type of tree used to store associative data structures. - [B-Tree](B-Tree/). A self-balancing search tree, in which nodes can have more than two children. - [QuadTree](QuadTree/). A tree with 4 children. -- [Octree](Octree/). A tree with 8 children. +- [Octree](Octree/). A tree with 8 children. ### Hashing @@ -208,7 +208,7 @@ For more information, check out these great books: - [The Algorithm Design Manual](http://www.algorist.com) by Skiena - [Elements of Programming Interviews](http://elementsofprogramminginterviews.com) by Aziz, Lee, Prakash - [Algorithms](http://www.cs.princeton.edu/~rs/) by Sedgewick -- [Grokking Algorithms](https://www.manning.com/books/grokking-algorithms) by Aditya Bhargava +- [Grokking Algorithms](https://www.manning.com/books/grokking-algorithms) by Aditya Bhargava The following books are available for free online: diff --git a/gfm-render.sh b/gfm-render.sh index 09c026d55..4e18c8560 100755 --- a/gfm-render.sh +++ b/gfm-render.sh @@ -1,50 +1,108 @@ #!/usr/bin/env bash -# $1 - readme +set -e + +# $1 - readme file name function render_markdown_to_html { - # escape escaping characters - if [[ $(uname) == "Darwin" ]]; then - content=$( - cat "$1" \ - | sed 's/\\/\\\\/g' \ - | sed 's/"/\\"/g' \ - | sed $'s/\t/\\\\t/g' \ - | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\\n/g' \ - ) - else - content=$( - cat "$1" \ - | sed 's/\\/\\\\/g' \ - | sed 's/"/\\"/g' \ - | sed 's/\t/\\t/g' \ - | sed ':a;N;$!ba;s/\n/\\n/g' \ - ) - fi + # escape escaping characters on Darwin only + content=$( + cat "$1" \ + | sed 's/\\/\\\\/g' \ + | sed 's/"/\\"/g' \ + | sed $'s/\t/\\\\t/g' \ + | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\\n/g' \ + ) # network call to GitHub API json="{\"text\":\"$content\",\"mode\":\"gfm\",\"context\":\"$USERNAME/swift-algorithm-club\"}" echo -e "$(curl -s --data "$json" -u $USERNAME:$TOKEN https://api.github.com/markdown)" } -# $1 - comment -function push_to_gh_pages { - git checkout -b gh-pages - git add . - git commit -m "$1" - git push -f https://$TOKEN@github.com/$USERNAME/swift-algorithm-club.git gh-pages -} - # download github systax highlight stylesheet echo "> Downloading github-light.css..." curl -s -O https://raw.githubusercontent.com/primer/github-syntax-light/master/lib/github-light.css +# slightly modify the main stylesheet +echo "> Modifying github-light.css..." +cat >> github-light.css << EOF +#container { + margin: 0 auto; + width: 75%; + min-width: 768px; + max-width: 896px; + position: relative; +} + +body { + font-size: 18px; +} + +code { + padding: 0.2em; + margin: 0; + font-size: 85%; + background-color: #f6f8fa; + line-height: 1.45; + border-radius: 3px +} + +pre code { + padding: 0px; + background-color: transparent; +} + +.highlight { + margin: 0px; + padding: 0px 16px; + font-size: 85%; + line-height: 1.45; + overflow: auto; + background-color: #f6f8fa; + border-radius: 3px; +} + +@media (max-width: 768px) { + #container { + position: absolute; + margin: 0; + width: 100%; + height: 100%; + min-width: 100%; + } +} +EOF + +# other markdown articles +for title in "What are Algorithms" "Big-O Notation" "Algorithm Design" "Why Algorithms"; do + echo "> Generating $title.html..." + + cat > "$title.html" << EOF + + + $title + + + +

    + + +EOF +done + # if index.html does not exist, create one; # otherwise, empty its content. -if [[ -z index.html ]]; then - touch index.html -else - > index.html -fi +echo "> Generating index.html..." +cat > index.html << EOF + + + Swift Algorithm Club + + + +
    $(render_markdown_to_html README.markdown | sed 's/.markdown/.html/g')
    + + +EOF # iterate immediate directories find . -maxdepth 1 -type d | while read folder; do @@ -54,53 +112,30 @@ find . -maxdepth 1 -type d | while read folder; do if [[ -f $folder/README.md ]]; then readme="$folder/README.md"; fi if [[ -f $folder/README.markdown ]]; then readme="$folder/README.markdown"; fi - # exclude the repository's README - if [[ !(-z $readme) && ($readme != "./README.markdown") ]]; then - name=$(basename "$folder") - echo "> Generating $name/index.html..." + # skip if there is no README or it it the README of the repository + if [[ (-z $readme) || $readme == "./README.markdown" ]]; then continue; fi + + # render README to HTML + name=$(basename "$folder") + echo "> Generating $name/index.html..." - cat > "$folder/index.html" << EOF + cat > "$folder/index.html" << EOF + $name - - $(render_markdown_to_html "$readme") +
    $(render_markdown_to_html "$readme")
    EOF - # temporarily write the list of HTML filenames to the main index.html - echo "$lists
  • $name
  • " >> index.html - fi done -echo "

    Swift Algorithm

      $(echo -n $(cat index.html))
    " > index.html - # push to gh-pages -if [[ $CI = true ]]; then push_to_gh_pages "Generated by TravisCI on $(date +%D)"; fi +if [[ $CI = true ]]; then + git checkout -b gh-pages + git add . + git commit -m "$Generated by TravisCI on $(date +%D)" + git push -f https://$TOKEN@github.com/$USERNAME/swift-algorithm-club.git gh-pages +fi From aa1c3f799020bc854a934b3b107ff97a8412ae5f Mon Sep 17 00:00:00 2001 From: n0an Date: Wed, 20 Dec 2017 13:49:51 +0300 Subject: [PATCH 032/327] RadixTree syntax updated to Swift 4 Characters removed (deprecated in Swift 4). Substring removed (deprecated in Swift 4). String slicing subscript used for substrings creation. --- .../Sources/RadixTree.swift | 46 +++++++++---------- Radix Tree/RadixTree.swift | 46 +++++++++---------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Radix Tree/RadixTree.playground/Sources/RadixTree.swift b/Radix Tree/RadixTree.playground/Sources/RadixTree.swift index 1914f57bc..77e289f7d 100644 --- a/Radix Tree/RadixTree.playground/Sources/RadixTree.swift +++ b/Radix Tree/RadixTree.playground/Sources/RadixTree.swift @@ -181,10 +181,10 @@ public class RadixTree { else if shared == e.label { currEdge = e var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = searchStr.characters.index(after: tempIndex) + for _ in 1...shared.count { + tempIndex = searchStr.index(after: tempIndex) } - searchStr = searchStr.substring(from: tempIndex) + searchStr = String(searchStr[tempIndex...]) found = true break } @@ -192,18 +192,18 @@ public class RadixTree { // If the child's label and the search string share a partial prefix, // then both the label and the search string need to be substringed // and a new branch needs to be created - else if shared.characters.count > 0 { - var labelIndex = e.label.characters.startIndex + else if shared.count > 0 { + var labelIndex = e.label.startIndex // Create index objects and move them to after the shared prefix - for _ in 1...shared.characters.count { - index = searchStr.characters.index(after: index) - labelIndex = e.label.characters.index(after: labelIndex) + for _ in 1...shared.count { + index = searchStr.index(after: index) + labelIndex = e.label.index(after: labelIndex) } // Substring both the search string and the label from the shared prefix - searchStr = searchStr.substring(from: index) - e.label = e.label.substring(from: labelIndex) + searchStr = String(searchStr[index...]) + e.label = String(e.label[labelIndex...]) // Create 2 new edges and update parent/children values let newEdge = Edge(e.label) @@ -266,16 +266,16 @@ public class RadixTree { if shared == c.label { currEdge = c var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = searchStr.characters.index(after: tempIndex) + for _ in 1...shared.count { + tempIndex = searchStr.index(after: tempIndex) } - searchStr = searchStr.substring(from: tempIndex) + searchStr = String(searchStr[tempIndex...]) found = true break } // If the shared string is empty, go to the next child - else if shared.characters.count == 0 { + else if shared.count == 0 { continue } @@ -287,7 +287,7 @@ public class RadixTree { // If the search string and the child's label only share some characters, // the string is not in the tree, return false else if shared[shared.startIndex] == c.label[c.label.startIndex] && - shared.characters.count < c.label.characters.count { + shared.count < c.label.count { return false } } @@ -340,10 +340,10 @@ public class RadixTree { if shared == currEdge.children[c].label { currEdge = currEdge.children[c] var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = searchStr.characters.index(after: tempIndex) + for _ in 1...shared.count { + tempIndex = searchStr.index(after: tempIndex) } - searchStr = searchStr.substring(from: tempIndex) + searchStr = String(searchStr[tempIndex...]) found = true break } @@ -366,13 +366,13 @@ public class RadixTree { // i.e. sharedPrefix("court", "coral") -> "co" public func sharedPrefix(_ str1: String, _ str2: String) -> String { var temp = "" - var c1 = str1.characters.startIndex - var c2 = str2.characters.startIndex - for _ in 0...min(str1.characters.count-1, str2.characters.count-1) { + var c1 = str1.startIndex + var c2 = str2.startIndex + for _ in 0...min(str1.count-1, str2.count-1) { if str1[c1] == str2[c2] { temp.append( str1[c1] ) - c1 = str1.characters.index(after:c1) - c2 = str2.characters.index(after:c2) + c1 = str1.index(after:c1) + c2 = str2.index(after:c2) } else { return temp } diff --git a/Radix Tree/RadixTree.swift b/Radix Tree/RadixTree.swift index 958ffb4e6..943000dd3 100644 --- a/Radix Tree/RadixTree.swift +++ b/Radix Tree/RadixTree.swift @@ -181,10 +181,10 @@ public class RadixTree { else if shared == e.label { currEdge = e var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = searchStr.characters.index(after: tempIndex) + for _ in 1...shared.count { + tempIndex = searchStr.index(after: tempIndex) } - searchStr = searchStr.substring(from: tempIndex) + searchStr = String(searchStr[tempIndex...]) found = true break } @@ -192,18 +192,18 @@ public class RadixTree { // If the child's label and the search string share a partial prefix, // then both the label and the search string need to be substringed // and a new branch needs to be created - else if shared.characters.count > 0 { - var labelIndex = e.label.characters.startIndex + else if shared.count > 0 { + var labelIndex = e.label.startIndex // Create index objects and move them to after the shared prefix - for _ in 1...shared.characters.count { - index = searchStr.characters.index(after: index) - labelIndex = e.label.characters.index(after: labelIndex) + for _ in 1...shared.count { + index = searchStr.index(after: index) + labelIndex = e.label.index(after: labelIndex) } // Substring both the search string and the label from the shared prefix - searchStr = searchStr.substring(from: index) - e.label = e.label.substring(from: labelIndex) + searchStr = String(searchStr[index...]) + e.label = String(e.label[labelIndex...]) // Create 2 new edges and update parent/children values let newEdge = Edge(e.label) @@ -266,16 +266,16 @@ public class RadixTree { if shared == c.label { currEdge = c var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = searchStr.characters.index(after: tempIndex) + for _ in 1...shared.count { + tempIndex = searchStr.index(after: tempIndex) } - searchStr = searchStr.substring(from: tempIndex) + searchStr = String(searchStr[tempIndex...]) found = true break } // If the shared string is empty, go to the next child - else if shared.characters.count == 0 { + else if shared.count == 0 { continue } @@ -287,7 +287,7 @@ public class RadixTree { // If the search string and the child's label only share some characters, // the string is not in the tree, return false else if shared[shared.startIndex] == c.label[c.label.startIndex] && - shared.characters.count < c.label.characters.count { + shared.count < c.label.count { return false } } @@ -340,10 +340,10 @@ public class RadixTree { if shared == currEdge.children[c].label { currEdge = currEdge.children[c] var tempIndex = searchStr.startIndex - for _ in 1...shared.characters.count { - tempIndex = searchStr.characters.index(after: tempIndex) + for _ in 1...shared.count { + tempIndex = searchStr.index(after: tempIndex) } - searchStr = searchStr.substring(from: tempIndex) + searchStr = String(searchStr[tempIndex...]) found = true break } @@ -366,13 +366,13 @@ public class RadixTree { // i.e. sharedPrefix("court", "coral") -> "co" public func sharedPrefix(_ str1: String, _ str2: String) -> String { var temp = "" - var c1 = str1.characters.startIndex - var c2 = str2.characters.startIndex - for _ in 0...min(str1.characters.count-1, str2.characters.count-1) { + var c1 = str1.startIndex + var c2 = str2.startIndex + for _ in 0...min(str1.count-1, str2.count-1) { if str1[c1] == str2[c2] { temp.append( str1[c1] ) - c1 = str1.characters.index(after:c1) - c2 = str2.characters.index(after:c2) + c1 = str1.index(after:c1) + c2 = str2.index(after:c2) } else { return temp } From f035a25111c9d87335a187afcedda77afd4d7ee4 Mon Sep 17 00:00:00 2001 From: Aamir Anwar Date: Fri, 22 Dec 2017 16:02:39 +0530 Subject: [PATCH 033/327] Fixed typo in the README for the word 'example' --- Splay Tree/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Splay Tree/readme.md b/Splay Tree/readme.md index 2c5e87ed7..f3b852f22 100644 --- a/Splay Tree/readme.md +++ b/Splay Tree/readme.md @@ -159,7 +159,7 @@ Now suppose a *insert(7)* operation was performed and we're in a *ZigZag* case. ## Advantages -Splay trees provide an efficient way to quickly access elements that are frequently requested. This characteristic makes then a good choice to implement, for exmaple, caches or garbage collection algorithms, or in any other problem involving frequent access to a certain numbers of elements from a data set. +Splay trees provide an efficient way to quickly access elements that are frequently requested. This characteristic makes then a good choice to implement, for example, caches or garbage collection algorithms, or in any other problem involving frequent access to a certain numbers of elements from a data set. ## Disadvantages From bcd0896b446c91c76a2e758bd8add3b882fa5126 Mon Sep 17 00:00:00 2001 From: Hemang Date: Wed, 3 Jan 2018 12:06:27 +0530 Subject: [PATCH 034/327] Update README.markdown Corrected the Written by (Author) URL for Palindrome algorithm. --- Palindromes/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index 18518adbe..69520a132 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -104,4 +104,4 @@ racecar -> left index == right index -> return true [Palindrome Wikipedia](https://en.wikipedia.org/wiki/Palindrome) -*Written by [Joshua Alvarado](https://github.com/https://github.com/lostatseajoshua)* +*Written by [Joshua Alvarado](https://github.com/lostatseajoshua)* From a51f98aa0737063e5dc882c19df22b9de388bccf Mon Sep 17 00:00:00 2001 From: Keith Date: Thu, 4 Jan 2018 16:29:14 +0800 Subject: [PATCH 035/327] Fix a spelling mistake change the `probablistic` to `probabilistic` --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 46544682e..7c9482d0c 100644 --- a/README.markdown +++ b/README.markdown @@ -145,7 +145,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types ### Lists - [Linked List](Linked%20List/). A sequence of data items connected through links. Covers both singly and doubly linked lists. -- [Skip-List](Skip-List/). Skip List is a probablistic data-structure with same logarithmic time bound and efficiency as AVL/ or Red-Black tree and provides a clever compromise to efficiently support search and update operations. +- [Skip-List](Skip-List/). Skip List is a probabilistic data-structure with same logarithmic time bound and efficiency as AVL/ or Red-Black tree and provides a clever compromise to efficiently support search and update operations. ### Trees From 677e3cefa18c9a815d7d2509e1198553c7a63468 Mon Sep 17 00:00:00 2001 From: Giuseppe Lanza Date: Thu, 4 Jan 2018 14:48:07 +0000 Subject: [PATCH 036/327] IntroSort playground implementation --- Introsort/Introsort.playground/Contents.swift | 41 +++++++++++++++ .../Sources/HeapSort.swift | 50 +++++++++++++++++++ .../Sources/InsertionSort.swift | 28 +++++++++++ .../Sources/Partition.swift | 43 ++++++++++++++++ .../Sources/Randomize.swift | 9 ++++ .../Introsort.playground/Sources/Sort3.swift | 21 ++++++++ .../contents.xcplayground | 4 ++ 7 files changed, 196 insertions(+) create mode 100644 Introsort/Introsort.playground/Contents.swift create mode 100644 Introsort/Introsort.playground/Sources/HeapSort.swift create mode 100644 Introsort/Introsort.playground/Sources/InsertionSort.swift create mode 100644 Introsort/Introsort.playground/Sources/Partition.swift create mode 100644 Introsort/Introsort.playground/Sources/Randomize.swift create mode 100644 Introsort/Introsort.playground/Sources/Sort3.swift create mode 100644 Introsort/Introsort.playground/contents.xcplayground diff --git a/Introsort/Introsort.playground/Contents.swift b/Introsort/Introsort.playground/Contents.swift new file mode 100644 index 000000000..43ee02e3f --- /dev/null +++ b/Introsort/Introsort.playground/Contents.swift @@ -0,0 +1,41 @@ +//: Playground - noun: a place where people can play + +import Foundation + +func introsort(_ array: inout [T], by areInIncreasingOrder: (T, T) -> Bool) { + //The depth limit is as best practice 2 * log( n ) + let depthLimit = 2 * floor(log2(Double(array.count))) + + introSortImplementation(for: &array, range: 0..(for array: inout [T], range: Range, depthLimit: Int, by areInIncreasingOrder: (T, T) -> Bool) { + if array.distance(from: range.lowerBound, to: range.upperBound) < 20 { + //if the partition count is less than 20 we can sort it using insertion sort. This algorithm in fact performs well on collections + //of this size, plus, at this point is quite probable that the quisksort part of the algorithm produced a partition which is + //nearly sorted. As we knoe insertion sort tends to O( n ) if this is the case. + insertionSort(for: &array, range: range, by: areInIncreasingOrder) + } else if depthLimit == 0 { + //If we reached the depth limit for this recursion branch, it's possible that we are hitting quick sort's worst case. + //Since quicksort degrades to O( n^2 ) in its worst case we stop using quicksort for this recursion branch and we switch to heapsort. + //Our preference remains quicksort, and we hope to be rare to see this condition to be true + heapsort(for: &array, range: range, by: areInIncreasingOrder) + } else { + //By default we use quicksort to sort our collection. The partition index method chose a pivot, and puts all the + //elements less than pivot on the left, and the ones bigger than pivot on the right. At the end of the operation the + //position of the pivot in the array is returned so that we can form the two partitions. + let partIdx = partitionIndex(for: &array, subRange: range, by: areInIncreasingOrder) + + //We can recursively call introsort implementation, decreasing the depthLimit for the left partition and the right partition. + introSortImplementation(for: &array, range: range.lowerBound..(_ elements: inout [T], _ index: Int, _ range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + let countToIndex = elements.distance(from: range.lowerBound, to: index) + let countFromIndex = elements.distance(from: index, to: range.upperBound) + + guard countToIndex + 1 < countFromIndex else { return } + + let left = elements.index(index, offsetBy: countToIndex + 1) + var largest = index + if areInIncreasingOrder(elements[largest], elements[left]) { + largest = left + } + + if countToIndex + 2 < countFromIndex { + let right = elements.index(after: left) + if areInIncreasingOrder(elements[largest], elements[right]) { + largest = right + } + } + + if largest != index { + elements.swapAt(index, largest) + shiftDown(&elements, largest, range, by: areInIncreasingOrder) + } + +} + +private func heapify(_ list: inout [T], _ range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + let root = range.lowerBound + var node = list.index(root, offsetBy: list.distance(from: range.lowerBound, to: range.upperBound)/2) + + while node != root { + list.formIndex(before: &node) + shiftDown(&list, node, range, by: areInIncreasingOrder) + } +} + +public func heapsort(for array: inout [T], range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + var hi = range.upperBound + let lo = range.lowerBound + heapify(&array, range, by: areInIncreasingOrder) + array.formIndex(before: &hi) + + while hi != lo { + array.swapAt(lo, hi) + shiftDown(&array, lo, lo..(for array: inout [T], range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + guard !range.isEmpty else { return } + + let start = range.lowerBound + var sortedEnd = start + + array.formIndex(after: &sortedEnd) + while sortedEnd != range.upperBound { + let x = array[sortedEnd] + + var i = sortedEnd + repeat { + let predecessor = array[array.index(before: i)] + + guard areInIncreasingOrder(x, predecessor) else { break } + array[i] = predecessor + array.formIndex(before: &i) + } while i != start + + if i != sortedEnd { + array[i] = x + } + array.formIndex(after: &sortedEnd) + } + +} diff --git a/Introsort/Introsort.playground/Sources/Partition.swift b/Introsort/Introsort.playground/Sources/Partition.swift new file mode 100644 index 000000000..e24636da7 --- /dev/null +++ b/Introsort/Introsort.playground/Sources/Partition.swift @@ -0,0 +1,43 @@ +import Foundation + +public func partitionIndex(for elements: inout [T], subRange range: Range, by areInIncreasingOrder: (T, T) -> Bool) -> Int { + var lo = range.lowerBound + var hi = elements.index(before: range.upperBound) + + // Sort the first, middle, and last elements, then use the middle value + // as the pivot for the partition. + let half = elements.distance(from: lo, to: hi) / 2 + let mid = elements.index(lo, offsetBy: half) + + sort3(in: &elements, a: lo, b: mid, c: hi, by: areInIncreasingOrder) + let pivot = elements[mid] + + while true { + elements.formIndex(after: &lo) + guard findLo(in: elements, pivot: pivot, from: &lo, to: hi, by: areInIncreasingOrder) else { break } + elements.formIndex(before: &hi) + guard findHi(in: elements, pivot: pivot, from: lo, to: &hi, by: areInIncreasingOrder) else { break } + elements.swapAt(lo, hi) + } + + + return lo +} + +private func findLo(in array: [T], pivot: T, from lo: inout Int, to hi: Int, by areInIncreasingOrder: (T, T)->Bool) -> Bool { + while lo != hi { + if !areInIncreasingOrder(array[lo], pivot) { + return true + } + array.formIndex(after: &lo) + } + return false +} + +private func findHi(in array: [T], pivot: T, from lo: Int, to hi: inout Int, by areInIncreasingOrder: (T, T)->Bool) -> Bool { + while hi != lo { + if areInIncreasingOrder(array[hi], pivot) { return true } + array.formIndex(before: &hi) + } + return false +} diff --git a/Introsort/Introsort.playground/Sources/Randomize.swift b/Introsort/Introsort.playground/Sources/Randomize.swift new file mode 100644 index 000000000..6d1d57132 --- /dev/null +++ b/Introsort/Introsort.playground/Sources/Randomize.swift @@ -0,0 +1,9 @@ +import Foundation + +public func randomize(n: Int) -> [Int] { + var unsorted = [Int]() + for _ in 0..(in array: inout [T], a: Int, b: Int, c: Int, by areInIncreasingOrder: (T, T) -> Bool) { + switch (areInIncreasingOrder(array[b], array[a]), + areInIncreasingOrder(array[c], array[b])) { + case (false, false): break + case (true, true): array.swapAt(a, c) + case (true, false): + array.swapAt(a, b) + + if areInIncreasingOrder(array[c], array[b]) { + array.swapAt(b, c) + } + case (false, true): + array.swapAt(b, c) + + if areInIncreasingOrder(array[b], array[a]) { + array.swapAt(a, b) + } + } +} diff --git a/Introsort/Introsort.playground/contents.xcplayground b/Introsort/Introsort.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Introsort/Introsort.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 717ba94933686ea00068b5fc4ea0bc223c93cf38 Mon Sep 17 00:00:00 2001 From: Giuseppe Lanza Date: Thu, 4 Jan 2018 15:49:29 +0000 Subject: [PATCH 037/327] Added readme file --- Introsort/HeapSort.swift | 50 ++++++++++++++++ Introsort/InsertionSort.swift | 28 +++++++++ Introsort/IntroSort.swift | 32 ++++++++++ Introsort/Partition.swift | 43 +++++++++++++ Introsort/README.markdown | 110 ++++++++++++++++++++++++++++++++++ Introsort/Randomize.swift | 9 +++ Introsort/Sort3.swift | 21 +++++++ README.markdown | 4 ++ 8 files changed, 297 insertions(+) create mode 100644 Introsort/HeapSort.swift create mode 100644 Introsort/InsertionSort.swift create mode 100644 Introsort/IntroSort.swift create mode 100644 Introsort/Partition.swift create mode 100644 Introsort/README.markdown create mode 100644 Introsort/Randomize.swift create mode 100644 Introsort/Sort3.swift diff --git a/Introsort/HeapSort.swift b/Introsort/HeapSort.swift new file mode 100644 index 000000000..f5bc466da --- /dev/null +++ b/Introsort/HeapSort.swift @@ -0,0 +1,50 @@ +import Foundation + +private func shiftDown(_ elements: inout [T], _ index: Int, _ range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + let countToIndex = elements.distance(from: range.lowerBound, to: index) + let countFromIndex = elements.distance(from: index, to: range.upperBound) + + guard countToIndex + 1 < countFromIndex else { return } + + let left = elements.index(index, offsetBy: countToIndex + 1) + var largest = index + if areInIncreasingOrder(elements[largest], elements[left]) { + largest = left + } + + if countToIndex + 2 < countFromIndex { + let right = elements.index(after: left) + if areInIncreasingOrder(elements[largest], elements[right]) { + largest = right + } + } + + if largest != index { + elements.swapAt(index, largest) + shiftDown(&elements, largest, range, by: areInIncreasingOrder) + } + +} + +private func heapify(_ list: inout [T], _ range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + let root = range.lowerBound + var node = list.index(root, offsetBy: list.distance(from: range.lowerBound, to: range.upperBound)/2) + + while node != root { + list.formIndex(before: &node) + shiftDown(&list, node, range, by: areInIncreasingOrder) + } +} + +public func heapsort(for array: inout [T], range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + var hi = range.upperBound + let lo = range.lowerBound + heapify(&array, range, by: areInIncreasingOrder) + array.formIndex(before: &hi) + + while hi != lo { + array.swapAt(lo, hi) + shiftDown(&array, lo, lo..(for array: inout [T], range: Range, by areInIncreasingOrder: (T, T) -> Bool) { + guard !range.isEmpty else { return } + + let start = range.lowerBound + var sortedEnd = start + + array.formIndex(after: &sortedEnd) + while sortedEnd != range.upperBound { + let x = array[sortedEnd] + + var i = sortedEnd + repeat { + let predecessor = array[array.index(before: i)] + + guard areInIncreasingOrder(x, predecessor) else { break } + array[i] = predecessor + array.formIndex(before: &i) + } while i != start + + if i != sortedEnd { + array[i] = x + } + array.formIndex(after: &sortedEnd) + } + +} diff --git a/Introsort/IntroSort.swift b/Introsort/IntroSort.swift new file mode 100644 index 000000000..866b2603f --- /dev/null +++ b/Introsort/IntroSort.swift @@ -0,0 +1,32 @@ +import Foundation + +public func introsort(_ array: inout [T], by areInIncreasingOrder: (T, T) -> Bool) { + //The depth limit is as best practice 2 * log( n ) + let depthLimit = 2 * floor(log2(Double(array.count))) + + introSortImplementation(for: &array, range: 0..(for array: inout [T], range: Range, depthLimit: Int, by areInIncreasingOrder: (T, T) -> Bool) { + if array.distance(from: range.lowerBound, to: range.upperBound) < 20 { + //if the partition count is less than 20 we can sort it using insertion sort. This algorithm in fact performs well on collections + //of this size, plus, at this point is quite probable that the quisksort part of the algorithm produced a partition which is + //nearly sorted. As we knoe insertion sort tends to O( n ) if this is the case. + insertionSort(for: &array, range: range, by: areInIncreasingOrder) + } else if depthLimit == 0 { + //If we reached the depth limit for this recursion branch, it's possible that we are hitting quick sort's worst case. + //Since quicksort degrades to O( n^2 ) in its worst case we stop using quicksort for this recursion branch and we switch to heapsort. + //Our preference remains quicksort, and we hope to be rare to see this condition to be true + heapsort(for: &array, range: range, by: areInIncreasingOrder) + } else { + //By default we use quicksort to sort our collection. The partition index method chose a pivot, and puts all the + //elements less than pivot on the left, and the ones bigger than pivot on the right. At the end of the operation the + //position of the pivot in the array is returned so that we can form the two partitions. + let partIdx = partitionIndex(for: &array, subRange: range, by: areInIncreasingOrder) + + //We can recursively call introsort implementation, decreasing the depthLimit for the left partition and the right partition. + introSortImplementation(for: &array, range: range.lowerBound..(for elements: inout [T], subRange range: Range, by areInIncreasingOrder: (T, T) -> Bool) -> Int { + var lo = range.lowerBound + var hi = elements.index(before: range.upperBound) + + // Sort the first, middle, and last elements, then use the middle value + // as the pivot for the partition. + let half = elements.distance(from: lo, to: hi) / 2 + let mid = elements.index(lo, offsetBy: half) + + sort3(in: &elements, a: lo, b: mid, c: hi, by: areInIncreasingOrder) + let pivot = elements[mid] + + while true { + elements.formIndex(after: &lo) + guard findLo(in: elements, pivot: pivot, from: &lo, to: hi, by: areInIncreasingOrder) else { break } + elements.formIndex(before: &hi) + guard findHi(in: elements, pivot: pivot, from: lo, to: &hi, by: areInIncreasingOrder) else { break } + elements.swapAt(lo, hi) + } + + + return lo +} + +private func findLo(in array: [T], pivot: T, from lo: inout Int, to hi: Int, by areInIncreasingOrder: (T, T)->Bool) -> Bool { + while lo != hi { + if !areInIncreasingOrder(array[lo], pivot) { + return true + } + array.formIndex(after: &lo) + } + return false +} + +private func findHi(in array: [T], pivot: T, from lo: Int, to hi: inout Int, by areInIncreasingOrder: (T, T)->Bool) -> Bool { + while hi != lo { + if areInIncreasingOrder(array[hi], pivot) { return true } + array.formIndex(before: &hi) + } + return false +} diff --git a/Introsort/README.markdown b/Introsort/README.markdown new file mode 100644 index 000000000..c4ee6f804 --- /dev/null +++ b/Introsort/README.markdown @@ -0,0 +1,110 @@ +# IntroSort + +Goal: Sort an array from low to high (or high to low). + +IntroSort is the algorithm used by swift to sort a collection. Introsort is an hybrid algorithm invented by David Musser in 1993 with the purpose of giving a generic sorting algorithm for the C++ standard library. The classic implementation of introsort expect a recursive Quicksort with fallback to Heapsort in case the recursion depth level reached a certain max. The maximum depends on the number of elements in the collection and it is usually 2 * log(n). The reason behind this “fallback” is that if Quicksort was not able to get the solution after 2 * log(n) recursions for a branch, probably it hit its worst case and it is degrading to complexity O( n^2 ). To optimise even further this algorithm, the swift implementation introduce an extra step in each recursion where the partition is sorted using InsertionSort if the count of the partition is less than 20. + +The number 20 is an empiric number obtained observing the behaviour of InsertionSort with lists of this size. + +Here's an implementation in Pseudocode: + +``` +procedure sort(A : array): + let maxdepth = ⌊log(length(A))⌋ × 2 + introSort(A, maxdepth) + +procedure introsort(A, maxdepth): + n ← length(A) + if n < 20: + insertionsort(A) + else if maxdepth = 0: + heapsort(A) + else: + p ← partition(A) // the pivot is selected using median of 3 + introsort(A[0:p], maxdepth - 1) + introsort(A[p+1:n], maxdepth - 1) +``` + +## An example + +Let's walk through the example. The array is initially: + + [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ] + + +for this example let's assume that `maxDepth` is **2** and that the size of the partition for the insertionSort to kick in is **5** + +At the first iteration we run introSort on the full collection that counts 13 elements. the maxDepth is 2, therefore we fall in the else case where quicksort acts. + +The `partition` method picks the first element, the median and the last, it sorts them and uses the new median as pivot. + + [ 10, 8, 26 ] -> [ 8, 10, 26 ] + +Our array is now + + [ 8, 0, 3, 9, 2, 14, 10, 27, 1, 5, 8, -1, 26 ] + +**10** is the pivot. After the choice of the pivot, the `partition` method swaps elements to get all the elements less than pivot on the left, and all the elements more or equal than pivot on the right. + + [ 8, 0, 3, 9, 2, 1, 5, 8, -1, 10, 27, 14, 26 ] + +Because of the swaps, the index of of pivot is now changed and returned. The next step of introsort is to call recursively itself for the two sub arrays: + + less: [ 8, 0, 3, 9, 2, 1, 5, 8, -1, 10 ] + greater: [ 27, 14, 26 ] + +## maxDepth: 1, branch: less + + [ 8, 0, 3, 9, 2, 1, 5, 8, -1, 10 ] + +The count of the array is still more than 5 so we don't meet yet the conditions for insertion sort to kick in. At this iteration maxDepth is decreased by one but it is still more than zero, so heapsort will not act. + +Just like in the previous iteration quicksort wins and the `partition` method choses a pivot and sorts the elemets less than pivot on the left and the elements more or equeal than pivot on the right. + + array: [ 8, 0, 3, 9, 2, 1, 5, 8, -1, 10 ] + pivot candidates: [ 8, 1, 10] -> [ 1, 8, 10] + pivot: 8 + before partition: [ 1, 0, 3, 9, 2, 8, 5, 8, -1, 10 ] + after partition: [ 1, 0, 3, -1, 2, 5, 8, 8, 9, 10 ] + + less: [ 1, 0, 3, -1, 2, 5, 8 ] + greater: [ 8, 9, 10 ] + +## maxDepth: 0, branch: less + + [ 1, 0, 3, -1, 2, 5, 8 ] + +Just like before, introsort is recursively executed for `less` and greater. This time `less`has a count more than **5** so it will not be sorted with insertion sort, but the maxDepth decreased again by 1 is now 0 and heapsort takes over sorting the array. + + heapsort -> [ -1, 0, 1, 2, 3, 5, 8 ] + +## maxDepth: 0, branch: greater + + [ 8, 9, 10 ] + +following greater in this recursion, the count of elements is 3, which is less than 5, so this partition is sorted using insertionSort. + + insertionSort -> [ 8, 9 , 10] + + +## back to maxDepth = 1, branch: greater + + [ 27, 14, 26 ] + +At this point the original array has mutated to be + + [ -1, 0, 1, 2, 3, 5, 8, 8, 9, 10, 27, 14, 26 ] + +now the `less` partition is sorted and since the count of the `greater` partition is 3 it will be sorted with insertion sort `[ 14, 26, 27 ]` + +The array is now successfully sorted + + [ -1, 0, 1, 2, 3, 5, 8, 8, 9, 10, 14, 26, 27 ] + + +## See also + +[Introsort on Wikipedia](https://en.wikipedia.org/wiki/Introsort) +[Introsort comparison with other sorting algorithms](http://agostini.tech/2017/12/18/swift-sorting-algorithm/) + +*Written for Swift Algorithm Club by Giuseppe Lanza* diff --git a/Introsort/Randomize.swift b/Introsort/Randomize.swift new file mode 100644 index 000000000..6d1d57132 --- /dev/null +++ b/Introsort/Randomize.swift @@ -0,0 +1,9 @@ +import Foundation + +public func randomize(n: Int) -> [Int] { + var unsorted = [Int]() + for _ in 0..(in array: inout [T], a: Int, b: Int, c: Int, by areInIncreasingOrder: (T, T) -> Bool) { + switch (areInIncreasingOrder(array[b], array[a]), + areInIncreasingOrder(array[c], array[b])) { + case (false, false): break + case (true, true): array.swapAt(a, c) + case (true, false): + array.swapAt(a, b) + + if areInIncreasingOrder(array[c], array[b]) { + array.swapAt(b, c) + } + case (false, true): + array.swapAt(b, c) + + if areInIncreasingOrder(array[b], array[a]) { + array.swapAt(a, b) + } + } +} diff --git a/README.markdown b/README.markdown index 46544682e..beac173d6 100644 --- a/README.markdown +++ b/README.markdown @@ -73,6 +73,10 @@ Fast sorts: - [Merge Sort](Merge%20Sort/) - [Heap Sort](Heap%20Sort/) +Hybrid sorts: + +- [Introsort](Introsort/) + Special-purpose sorts: - [Counting Sort](Counting%20Sort/) From e30467bcc9a9681780cee9d7206f4e2bda776ac6 Mon Sep 17 00:00:00 2001 From: Davis Riedel Date: Sat, 6 Jan 2018 22:47:22 +0100 Subject: [PATCH 038/327] Improvements to Heap - renamed "elements" to "nodes" to clarify the difference between array and heap. This also unifies code and comments, which were sometimes referring to the array as "nodes". - made nodes publicly readable but only settable within the heap itself. To change the nodes/operate on the heap, the provided functions should be used, to guarantee the heaps structure. - renamed isOrderedBefore to orderCriteria. The variable name isOrderedBefore did not clearly explain what the variable is for/what the closure stored within does - added method to get node at a specific index - replace method should not force the replaced value to be higher/lower than its parent. Instead replace should remove the node to be replaced and insert the given value as a new one in order to preserve the heap's structure. Asserting crashes the whole program. - added @discardableResult to removeAt. If remove is @discardableResult removeAt should be as well in for consistency. - replaced while true in shiftDown with a recursive call. while true is bad programming style. - simplified indexOf method - added a removeNode method for heaps with equatable data type - improved, adjusted and added descriptions - made functions private where fileprivate was not needed - added tests for new functions and tested everything - updated README where necessary (to conform to new code, only a few changes) --- Heap/Heap.swift | 187 +++++++++--------- Heap/README.markdown | 12 +- Heap/Tests/HeapTests.swift | 97 +++++---- Heap/Tests/Tests.xcodeproj/project.pbxproj | 14 +- .../contents.xcworkspacedata | 0 .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 6 files changed, 172 insertions(+), 140 deletions(-) mode change 100644 => 100755 Heap/Heap.swift mode change 100644 => 100755 Heap/README.markdown mode change 100644 => 100755 Heap/Tests/HeapTests.swift mode change 100644 => 100755 Heap/Tests/Tests.xcodeproj/project.pbxproj mode change 100644 => 100755 Heap/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata mode change 100644 => 100755 Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme diff --git a/Heap/Heap.swift b/Heap/Heap.swift old mode 100644 new mode 100755 index b0355da5d..a33fc0b94 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -4,58 +4,55 @@ // public struct Heap { + /** The array that stores the heap's nodes. */ - var elements = [T]() + private(set) var nodes = [T]() - /** Determines whether this is a max-heap (>) or min-heap (<). */ - fileprivate var isOrderedBefore: (T, T) -> Bool + /** + * Determines how to compare two nodes in the heap. + * Use '>' for a max-heap or '<' for a min-heap, + * or provide a comparing method if the heap is made + * of custom elements, for example tuples. + */ + private var orderCriteria: (T, T) -> Bool /** * Creates an empty heap. * The sort function determines whether this is a min-heap or max-heap. - * For integers, > makes a max-heap, < makes a min-heap. + * For comparable data types, > makes a max-heap, < makes a min-heap. */ public init(sort: @escaping (T, T) -> Bool) { - self.isOrderedBefore = sort + self.orderCriteria = sort } /** * Creates a heap from an array. The order of the array does not matter; * the elements are inserted into the heap in the order determined by the - * sort function. + * sort function. For comparable data types, '>' makes a max-heap, + * '<' makes a min-heap. */ public init(array: [T], sort: @escaping (T, T) -> Bool) { - self.isOrderedBefore = sort + self.orderCriteria = sort buildHeap(fromArray: array) } - /* - // This version has O(n log n) performance. - private mutating func buildHeap(array: [T]) { - elements.reserveCapacity(array.count) - for value in array { - insert(value) - } - } - */ - /** - * Converts an array to a max-heap or min-heap in a bottom-up manner. + * Creates the max-heap or min-heap from an array, in a bottom-up manner. * Performance: This runs pretty much in O(n). */ - fileprivate mutating func buildHeap(fromArray array: [T]) { - elements = array - for i in stride(from: (elements.count/2 - 1), through: 0, by: -1) { - shiftDown(i, heapSize: elements.count) + private mutating func buildHeap(fromArray array: [T]) { + nodes = array + for i in stride(from: (nodes.count/2-1), through: 0, by: -1) { + shiftDown(i) } } public var isEmpty: Bool { - return elements.isEmpty + return nodes.isEmpty } public var count: Int { - return elements.count + return nodes.count } /** @@ -89,7 +86,13 @@ public struct Heap { * value (for a min-heap). */ public func peek() -> T? { - return elements.first + return nodes.first + } + + /** Returns the node at given index */ + public func node(at i: Int) -> T? { + guard i < nodes.count else { return nil } + return nodes[i] } /** @@ -97,10 +100,14 @@ public struct Heap { * or min-heap property still holds. Performance: O(log n). */ public mutating func insert(_ value: T) { - elements.append(value) - shiftUp(elements.count - 1) + nodes.append(value) + shiftUp(nodes.count - 1) } + /** + * Adds a sequence of values to the heap. This reorders the heap so that + * the max-heap or min-heap property still holds. Performance: O(log n). + */ public mutating func insert(_ sequence: S) where S.Iterator.Element == T { for value in sequence { insert(value) @@ -108,15 +115,14 @@ public struct Heap { } /** - * Allows you to change an element. In a max-heap, the new element should be - * larger than the old one; in a min-heap it should be smaller. + * Allows you to change an element. This reorders the heap so that + * the max-heap or min-heap property still holds. */ public mutating func replace(index i: Int, value: T) { - guard i < elements.count else { return } + guard i < nodes.count else { return } - assert(isOrderedBefore(value, elements[i])) - elements[i] = value - shiftUp(i) + removeAt(i) + insert(value) } /** @@ -124,34 +130,35 @@ public struct Heap { * value; for a min-heap it is the minimum value. Performance: O(log n). */ @discardableResult public mutating func remove() -> T? { - if elements.isEmpty { - return nil - } else if elements.count == 1 { - return elements.removeLast() - } else { - // Use the last node to replace the first one, then fix the heap by - // shifting this new first node into its proper position. - let value = elements[0] - elements[0] = elements.removeLast() - shiftDown() - return value + if !nodes.isEmpty { + if nodes.count == 1 { + return nodes.removeLast() + } else { + // Use the last node to replace the first one, then fix the heap by + // shifting this new first node into its proper position. + let value = nodes[0] + nodes[0] = nodes.removeLast() + shiftDown(0) + return value + } } + return nil } /** - * Removes an arbitrary node from the heap. Performance: O(log n). You need - * to know the node's index, which may actually take O(n) steps to find. + * Removes an arbitrary node from the heap. Performance: O(log n). + * Note that you need to know the node's index. */ - public mutating func removeAt(_ index: Int) -> T? { - guard index < elements.count else { return nil } + @discardableResult public mutating func removeAt(_ index: Int) -> T? { + guard index < nodes.count else { return nil } - let size = elements.count - 1 + let size = nodes.count - 1 if index != size { - elements.swapAt(index, size) - shiftDown(index, heapSize: size) + nodes.swapAt(index, size) + shiftDown(from: index, until: size) shiftUp(index) } - return elements.removeLast() + return nodes.removeLast() } /** @@ -160,68 +167,64 @@ public struct Heap { */ mutating func shiftUp(_ index: Int) { var childIndex = index - let child = elements[childIndex] + let child = nodes[childIndex] var parentIndex = self.parentIndex(ofIndex: childIndex) - while childIndex > 0 && isOrderedBefore(child, elements[parentIndex]) { - elements[childIndex] = elements[parentIndex] + while childIndex > 0 && orderCriteria(child, nodes[parentIndex]) { + nodes[childIndex] = nodes[parentIndex] childIndex = parentIndex parentIndex = self.parentIndex(ofIndex: childIndex) } - elements[childIndex] = child - } - - mutating func shiftDown() { - shiftDown(0, heapSize: elements.count) + nodes[childIndex] = child } /** * Looks at a parent node and makes sure it is still larger (max-heap) or * smaller (min-heap) than its childeren. */ - mutating func shiftDown(_ index: Int, heapSize: Int) { - var parentIndex = index + private mutating func shiftDown(from index: Int, until endIndex: Int) { + let leftChildIndex = self.leftChildIndex(ofIndex: index) + let rightChildIndex = leftChildIndex + 1 - while true { - let leftChildIndex = self.leftChildIndex(ofIndex: parentIndex) - let rightChildIndex = leftChildIndex + 1 - - // Figure out which comes first if we order them by the sort function: - // the parent, the left child, or the right child. If the parent comes - // first, we're done. If not, that element is out-of-place and we make - // it "float down" the tree until the heap property is restored. - var first = parentIndex - if leftChildIndex < heapSize && isOrderedBefore(elements[leftChildIndex], elements[first]) { - first = leftChildIndex - } - if rightChildIndex < heapSize && isOrderedBefore(elements[rightChildIndex], elements[first]) { - first = rightChildIndex - } - if first == parentIndex { return } - - elements.swapAt(parentIndex, first) - parentIndex = first + // Figure out which comes first if we order them by the sort function: + // the parent, the left child, or the right child. If the parent comes + // first, we're done. If not, that element is out-of-place and we make + // it "float down" the tree until the heap property is restored. + var first = index + if leftChildIndex < endIndex && orderCriteria(nodes[leftChildIndex], nodes[first]) { + first = leftChildIndex + } + if rightChildIndex < endIndex && orderCriteria(nodes[rightChildIndex], nodes[first]) { + first = rightChildIndex } + if first == index { return } + + nodes.swapAt(index, first) + shiftDown(from: first, until: endIndex) + } + + private mutating func shiftDown(_ index: Int) { + shiftDown(from: index, until: nodes.count) } + } // MARK: - Searching extension Heap where T: Equatable { - /** - * Searches the heap for the given element. Performance: O(n). - */ - public func index(of element: T) -> Int? { - return index(of: element, 0) + + /** Get the index of a node in the heap. Performance: O(n). */ + public func index(of node: T) -> Int? { + return nodes.index(where: { $0 == node }) } - fileprivate func index(of element: T, _ i: Int) -> Int? { - if i >= count { return nil } - if isOrderedBefore(element, elements[i]) { return nil } - if element == elements[i] { return i } - if let j = index(of: element, self.leftChildIndex(ofIndex: i)) { return j } - if let j = index(of: element, self.rightChildIndex(ofIndex: i)) { return j } + /** Removes the first occurrence of a node from the heap. Performance: O(n log n). */ + @discardableResult public mutating func remove(node: T) -> T? { + if let index = index(of: node) { + return removeAt(index) + } return nil } + } diff --git a/Heap/README.markdown b/Heap/README.markdown old mode 100644 new mode 100755 index 4344d9e7c..76d2bee39 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -38,7 +38,7 @@ A heap is not a replacement for a binary search tree, and there are similarities **Balancing.** A binary search tree must be "balanced" so that most operations have **O(log n)** performance. You can either insert and delete your data in a random order or use something like an [AVL tree](../AVL%20Tree/) or [red-black tree](../Red-Black%20Tree/), but with heaps we don't actually need the entire tree to be sorted. We just want the heap property to be fulfilled, so balancing isn't an issue. Because of the way the heap is structured, heaps can guarantee **O(log n)** performance. -**Searching.** Whereas searching is fast in a binary tree, it is slow in a heap. Searching isn't a top priority in a heap since the purpose of a heap is to put the largest (or smallest) node at the front and to allow relatively fast inserts and deletes. +**Searching.** Whereas searching is fast in a binary tree, it is slow in a heap. Searching isn't a top priority in a heap since the purpose of a heap is to put the largest (or smallest) node at the front and to allow relatively fast inserts and deletes. ## The tree inside an array @@ -148,7 +148,7 @@ There are two primitive operations necessary to make sure the heap is a valid ma Shifting up or down is a recursive procedure that takes **O(log n)** time. -Here are other operations that are built on primitive operations: +Here are other operations that are built on primitive operations: - `insert(value)`: Adds the new element to the end of the heap and then uses `shiftUp()` to fix the heap. @@ -190,7 +190,7 @@ The `(16)` was added to the first available space on the last row. Unfortunately, the heap property is no longer satisfied because `(2)` is above `(16)`, and we want higher numbers above lower numbers. (This is a max-heap.) -To restore the heap property, we swap `(16)` and `(2)`. +To restore the heap property, we swap `(16)` and `(2)`. ![The heap before insertion](Images/Insert2.png) @@ -214,7 +214,7 @@ What happens to the empty spot at the top? ![The root is gone](Images/Remove1.png) -When inserting, we put the new value at the end of the array. Here, we do the opposite: we take the last object we have, stick it up on top of the tree, and restore the heap property. +When inserting, we put the new value at the end of the array. Here, we do the opposite: we take the last object we have, stick it up on top of the tree, and restore the heap property. ![The last node goes to the root](Images/Remove2.png) @@ -226,7 +226,7 @@ Keep shifting down until the node does not have any children or it is larger tha ![The last node goes to the root](Images/Remove4.png) -The time required for shifting all the way down is proportional to the height of the tree which takes **O(log n)** time. +The time required for shifting all the way down is proportional to the height of the tree which takes **O(log n)** time. > **Note:** `shiftUp()` and `shiftDown()` can only fix one out-of-place element at a time. If there are multiple elements in the wrong place, you need to call these functions once for each of those elements. @@ -279,7 +279,7 @@ In code: ```swift private mutating func buildHeap(fromArray array: [T]) { elements = array - for i in (elements.count/2 - 1).stride(through: 0, by: -1) { + for i in stride(from: (nodes.count/2-1), through: 0, by: -1) { shiftDown(index: i, heapSize: elements.count) } } diff --git a/Heap/Tests/HeapTests.swift b/Heap/Tests/HeapTests.swift old mode 100644 new mode 100755 index 66be0931c..36035fe93 --- a/Heap/Tests/HeapTests.swift +++ b/Heap/Tests/HeapTests.swift @@ -19,9 +19,9 @@ class HeapTests: XCTestCase { let left = h.leftChildIndex(ofIndex: i) let right = h.rightChildIndex(ofIndex: i) let parent = h.parentIndex(ofIndex: i) - if left < h.count && h.elements[i] < h.elements[left] { return false } - if right < h.count && h.elements[i] < h.elements[right] { return false } - if i > 0 && h.elements[parent] < h.elements[i] { return false } + if left < h.count && h.nodes[i] < h.nodes[left] { return false } + if right < h.count && h.nodes[i] < h.nodes[right] { return false } + if i > 0 && h.nodes[parent] < h.nodes[i] { return false } } return true } @@ -31,9 +31,9 @@ class HeapTests: XCTestCase { let left = h.leftChildIndex(ofIndex: i) let right = h.rightChildIndex(ofIndex: i) let parent = h.parentIndex(ofIndex: i) - if left < h.count && h.elements[i] > h.elements[left] { return false } - if right < h.count && h.elements[i] > h.elements[right] { return false } - if i > 0 && h.elements[parent] > h.elements[i] { return false } + if left < h.count && h.nodes[i] > h.nodes[left] { return false } + if right < h.count && h.nodes[i] > h.nodes[right] { return false } + if i > 0 && h.nodes[parent] > h.nodes[i] { return false } } return true } @@ -90,7 +90,7 @@ class HeapTests: XCTestCase { let h1 = Heap(array: [1, 2, 3, 4, 5, 6, 7], sort: >) XCTAssertTrue(verifyMaxHeap(h1)) XCTAssertFalse(verifyMinHeap(h1)) - XCTAssertEqual(h1.elements, [7, 5, 6, 4, 2, 1, 3]) + XCTAssertEqual(h1.nodes, [7, 5, 6, 4, 2, 1, 3]) XCTAssertFalse(h1.isEmpty) XCTAssertEqual(h1.count, 7) XCTAssertEqual(h1.peek()!, 7) @@ -98,7 +98,7 @@ class HeapTests: XCTestCase { let h2 = Heap(array: [7, 6, 5, 4, 3, 2, 1], sort: >) XCTAssertTrue(verifyMaxHeap(h2)) XCTAssertFalse(verifyMinHeap(h2)) - XCTAssertEqual(h2.elements, [7, 6, 5, 4, 3, 2, 1]) + XCTAssertEqual(h2.nodes, [7, 6, 5, 4, 3, 2, 1]) XCTAssertFalse(h2.isEmpty) XCTAssertEqual(h2.count, 7) XCTAssertEqual(h2.peek()!, 7) @@ -106,7 +106,7 @@ class HeapTests: XCTestCase { let h3 = Heap(array: [4, 1, 3, 2, 16, 9, 10, 14, 8, 7], sort: >) XCTAssertTrue(verifyMaxHeap(h3)) XCTAssertFalse(verifyMinHeap(h3)) - XCTAssertEqual(h3.elements, [16, 14, 10, 8, 7, 9, 3, 2, 4, 1]) + XCTAssertEqual(h3.nodes, [16, 14, 10, 8, 7, 9, 3, 2, 4, 1]) XCTAssertFalse(h3.isEmpty) XCTAssertEqual(h3.count, 10) XCTAssertEqual(h3.peek()!, 16) @@ -114,7 +114,7 @@ class HeapTests: XCTestCase { let h4 = Heap(array: [27, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0], sort: >) XCTAssertTrue(verifyMaxHeap(h4)) XCTAssertFalse(verifyMinHeap(h4)) - XCTAssertEqual(h4.elements, [27, 17, 10, 16, 13, 9, 1, 5, 7, 12, 4, 8, 3, 0]) + XCTAssertEqual(h4.nodes, [27, 17, 10, 16, 13, 9, 1, 5, 7, 12, 4, 8, 3, 0]) XCTAssertFalse(h4.isEmpty) XCTAssertEqual(h4.count, 14) XCTAssertEqual(h4.peek()!, 27) @@ -124,7 +124,7 @@ class HeapTests: XCTestCase { let h1 = Heap(array: [1, 2, 3, 4, 5, 6, 7], sort: <) XCTAssertTrue(verifyMinHeap(h1)) XCTAssertFalse(verifyMaxHeap(h1)) - XCTAssertEqual(h1.elements, [1, 2, 3, 4, 5, 6, 7]) + XCTAssertEqual(h1.nodes, [1, 2, 3, 4, 5, 6, 7]) XCTAssertFalse(h1.isEmpty) XCTAssertEqual(h1.count, 7) XCTAssertEqual(h1.peek()!, 1) @@ -132,7 +132,7 @@ class HeapTests: XCTestCase { let h2 = Heap(array: [7, 6, 5, 4, 3, 2, 1], sort: <) XCTAssertTrue(verifyMinHeap(h2)) XCTAssertFalse(verifyMaxHeap(h2)) - XCTAssertEqual(h2.elements, [1, 3, 2, 4, 6, 7, 5]) + XCTAssertEqual(h2.nodes, [1, 3, 2, 4, 6, 7, 5]) XCTAssertFalse(h2.isEmpty) XCTAssertEqual(h2.count, 7) XCTAssertEqual(h2.peek()!, 1) @@ -140,7 +140,7 @@ class HeapTests: XCTestCase { let h3 = Heap(array: [4, 1, 3, 2, 16, 9, 10, 14, 8, 7], sort: <) XCTAssertTrue(verifyMinHeap(h3)) XCTAssertFalse(verifyMaxHeap(h3)) - XCTAssertEqual(h3.elements, [1, 2, 3, 4, 7, 9, 10, 14, 8, 16]) + XCTAssertEqual(h3.nodes, [1, 2, 3, 4, 7, 9, 10, 14, 8, 16]) XCTAssertFalse(h3.isEmpty) XCTAssertEqual(h3.count, 10) XCTAssertEqual(h3.peek()!, 1) @@ -148,7 +148,7 @@ class HeapTests: XCTestCase { let h4 = Heap(array: [27, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0], sort: <) XCTAssertTrue(verifyMinHeap(h4)) XCTAssertFalse(verifyMaxHeap(h4)) - XCTAssertEqual(h4.elements, [0, 4, 1, 5, 12, 8, 3, 16, 7, 17, 13, 10, 9, 27]) + XCTAssertEqual(h4.nodes, [0, 4, 1, 5, 12, 8, 3, 16, 7, 17, 13, 10, 9, 27]) XCTAssertFalse(h4.isEmpty) XCTAssertEqual(h4.count, 14) XCTAssertEqual(h4.peek()!, 0) @@ -158,14 +158,14 @@ class HeapTests: XCTestCase { let heap = Heap(array: [1, 1, 1, 1, 1], sort: >) XCTAssertTrue(verifyMaxHeap(heap)) XCTAssertTrue(verifyMinHeap(heap)) - XCTAssertEqual(heap.elements, [1, 1, 1, 1, 1]) + XCTAssertEqual(heap.nodes, [1, 1, 1, 1, 1]) } func testCreateMinHeapEqualElements() { let heap = Heap(array: [1, 1, 1, 1, 1], sort: <) XCTAssertTrue(verifyMinHeap(heap)) XCTAssertTrue(verifyMaxHeap(heap)) - XCTAssertEqual(heap.elements, [1, 1, 1, 1, 1]) + XCTAssertEqual(heap.nodes, [1, 1, 1, 1, 1]) } fileprivate func randomArray(_ n: Int) -> [Int] { @@ -183,7 +183,7 @@ class HeapTests: XCTestCase { XCTAssertTrue(verifyMaxHeap(h)) XCTAssertFalse(h.isEmpty) XCTAssertEqual(h.count, n) - XCTAssertTrue(isPermutation(a, h.elements)) + XCTAssertTrue(isPermutation(a, h.nodes)) } } @@ -194,58 +194,58 @@ class HeapTests: XCTestCase { XCTAssertTrue(verifyMinHeap(h)) XCTAssertFalse(h.isEmpty) XCTAssertEqual(h.count, n) - XCTAssertTrue(isPermutation(a, h.elements)) + XCTAssertTrue(isPermutation(a, h.nodes)) } } - func testRemoving() { + func testRemovingAtIndex() { var h = Heap(array: [100, 50, 70, 10, 20, 60, 65], sort: >) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 60, 65]) + XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 60, 65]) //test index out of bounds let v = h.removeAt(10) XCTAssertEqual(v, nil) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 60, 65]) + XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 60, 65]) let v1 = h.removeAt(5) XCTAssertEqual(v1, 60) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [100, 50, 70, 10, 20, 65]) + XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 65]) let v2 = h.removeAt(4) XCTAssertEqual(v2, 20) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [100, 65, 70, 10, 50]) + XCTAssertEqual(h.nodes, [100, 65, 70, 10, 50]) let v3 = h.removeAt(4) XCTAssertEqual(v3, 50) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [100, 65, 70, 10]) + XCTAssertEqual(h.nodes, [100, 65, 70, 10]) let v4 = h.removeAt(0) XCTAssertEqual(v4, 100) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [70, 65, 10]) + XCTAssertEqual(h.nodes, [70, 65, 10]) XCTAssertEqual(h.peek()!, 70) let v5 = h.remove() XCTAssertEqual(v5, 70) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [65, 10]) + XCTAssertEqual(h.nodes, [65, 10]) XCTAssertEqual(h.peek()!, 65) let v6 = h.remove() XCTAssertEqual(v6, 65) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [10]) + XCTAssertEqual(h.nodes, [10]) XCTAssertEqual(h.peek()!, 10) let v7 = h.remove() XCTAssertEqual(v7, 10) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, []) + XCTAssertEqual(h.nodes, []) XCTAssertNil(h.peek()) } @@ -259,12 +259,23 @@ class HeapTests: XCTestCase { func testRemoveRoot() { var h = Heap(array: [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1], sort: >) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1]) + XCTAssertEqual(h.nodes, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1]) XCTAssertEqual(h.peek()!, 15) let v = h.remove() XCTAssertEqual(v, 15) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [13, 12, 9, 5, 6, 8, 7, 4, 0, 1, 2]) + XCTAssertEqual(h.nodes, [13, 12, 9, 5, 6, 8, 7, 4, 0, 1, 2]) + } + + func testRemoveNode() { + var h = Heap(array: [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1], sort: >) + XCTAssertTrue(verifyMaxHeap(h)) + XCTAssertEqual(h.nodes, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1]) + XCTAssertEqual(h.node(at: 3)!, 5) + let v = h.remove(node: 5) + XCTAssertEqual(v, 5) + XCTAssertTrue(verifyMaxHeap(h)) + XCTAssertFalse(h.nodes.contains(5)) } func testRemoveRandomItems() { @@ -272,19 +283,27 @@ class HeapTests: XCTestCase { var a = randomArray(n) var h = Heap(array: a, sort: >) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertTrue(isPermutation(a, h.elements)) + XCTAssertTrue(isPermutation(a, h.nodes)) let m = (n + 1)/2 for k in 1...m { let i = Int(arc4random_uniform(UInt32(n - k + 1))) - let v = h.removeAt(i)! - let j = a.index(of: v)! + + var v: Int? = nil + if k == 2 || k == m { + v = h.remove(node: h.node(at: i)!) + } else { + v = h.removeAt(i) + } + XCTAssertNotNil(v) + + let j = a.index(of: v!)! a.remove(at: j) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.count, a.count) XCTAssertEqual(h.count, n - k) - XCTAssertTrue(isPermutation(a, h.elements)) + XCTAssertTrue(isPermutation(a, h.nodes)) } } } @@ -292,17 +311,17 @@ class HeapTests: XCTestCase { func testInsert() { var h = Heap(array: [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1], sort: >) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1]) + XCTAssertEqual(h.nodes, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1]) h.insert(10) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [15, 13, 10, 5, 12, 9, 7, 4, 0, 6, 2, 1, 8]) + XCTAssertEqual(h.nodes, [15, 13, 10, 5, 12, 9, 7, 4, 0, 6, 2, 1, 8]) } func testInsertArrayAndRemove() { var heap = Heap(sort: >) heap.insert([1, 3, 2, 7, 5, 9]) - XCTAssertEqual(heap.elements, [9, 5, 7, 1, 3, 2]) + XCTAssertEqual(heap.nodes, [9, 5, 7, 1, 3, 2]) XCTAssertEqual(9, heap.remove()) XCTAssertEqual(7, heap.remove()) @@ -316,15 +335,13 @@ class HeapTests: XCTestCase { func testReplace() { var h = Heap(array: [16, 14, 10, 8, 7, 9, 3, 2, 4, 1], sort: >) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [16, 14, 10, 8, 7, 9, 3, 2, 4, 1]) h.replace(index: 5, value: 13) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [16, 14, 13, 8, 7, 10, 3, 2, 4, 1]) //test index out of bounds h.replace(index: 20, value: 2) XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.elements, [16, 14, 13, 8, 7, 10, 3, 2, 4, 1]) } + } diff --git a/Heap/Tests/Tests.xcodeproj/project.pbxproj b/Heap/Tests/Tests.xcodeproj/project.pbxproj old mode 100644 new mode 100755 index 617e29f27..51433ee64 --- a/Heap/Tests/Tests.xcodeproj/project.pbxproj +++ b/Heap/Tests/Tests.xcodeproj/project.pbxproj @@ -83,7 +83,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0920; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { @@ -141,14 +141,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -187,14 +193,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/Heap/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Heap/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata old mode 100644 new mode 100755 diff --git a/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme old mode 100644 new mode 100755 index 80ed35600..77d01bebc --- a/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 8 Jan 2018 10:47:59 +0100 Subject: [PATCH 039/327] - Adopted discussed improvements - Made nodes and some other methods internal, so that extensions like HeapSort can use them. This fixes the HeapSort algorithm as well as the tests for both. --- Heap Sort/HeapSort.swift | 8 +++--- Heap/Heap.swift | 55 +++++++++++++++++--------------------- Heap/Tests/HeapTests.swift | 39 +++++++-------------------- 3 files changed, 38 insertions(+), 64 deletions(-) diff --git a/Heap Sort/HeapSort.swift b/Heap Sort/HeapSort.swift index 6b5e91dc5..0354817a6 100644 --- a/Heap Sort/HeapSort.swift +++ b/Heap Sort/HeapSort.swift @@ -1,10 +1,10 @@ extension Heap { public mutating func sort() -> [T] { - for i in stride(from: (elements.count - 1), through: 1, by: -1) { - elements.swapAt(0, i) - shiftDown(0, heapSize: i) + for i in stride(from: (nodes.count - 1), through: 1, by: -1) { + nodes.swapAt(0, i) + shiftDown(from: 0, until: i) } - return elements + return nodes } } diff --git a/Heap/Heap.swift b/Heap/Heap.swift index a33fc0b94..ae392d448 100755 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -6,7 +6,7 @@ public struct Heap { /** The array that stores the heap's nodes. */ - private(set) var nodes = [T]() + internal var nodes = [T]() /** * Determines how to compare two nodes in the heap. @@ -33,14 +33,14 @@ public struct Heap { */ public init(array: [T], sort: @escaping (T, T) -> Bool) { self.orderCriteria = sort - buildHeap(fromArray: array) + configureHeap(from: array) } /** - * Creates the max-heap or min-heap from an array, in a bottom-up manner. + * Configures the max-heap or min-heap from an array, in a bottom-up manner. * Performance: This runs pretty much in O(n). */ - private mutating func buildHeap(fromArray array: [T]) { + private mutating func configureHeap(from array: [T]) { nodes = array for i in stride(from: (nodes.count/2-1), through: 0, by: -1) { shiftDown(i) @@ -59,7 +59,7 @@ public struct Heap { * Returns the index of the parent of the element at index i. * The element at index 0 is the root of the tree and has no parent. */ - @inline(__always) func parentIndex(ofIndex i: Int) -> Int { + @inline(__always) internal func parentIndex(ofIndex i: Int) -> Int { return (i - 1) / 2 } @@ -68,7 +68,7 @@ public struct Heap { * Note that this index can be greater than the heap size, in which case * there is no left child. */ - @inline(__always) func leftChildIndex(ofIndex i: Int) -> Int { + @inline(__always) internal func leftChildIndex(ofIndex i: Int) -> Int { return 2*i + 1 } @@ -77,7 +77,7 @@ public struct Heap { * Note that this index can be greater than the heap size, in which case * there is no right child. */ - @inline(__always) func rightChildIndex(ofIndex i: Int) -> Int { + @inline(__always) internal func rightChildIndex(ofIndex i: Int) -> Int { return 2*i + 2 } @@ -89,12 +89,6 @@ public struct Heap { return nodes.first } - /** Returns the node at given index */ - public func node(at i: Int) -> T? { - guard i < nodes.count else { return nil } - return nodes[i] - } - /** * Adds a new value to the heap. This reorders the heap so that the max-heap * or min-heap property still holds. Performance: O(log n). @@ -121,7 +115,7 @@ public struct Heap { public mutating func replace(index i: Int, value: T) { guard i < nodes.count else { return } - removeAt(i) + remove(at: i) insert(value) } @@ -130,26 +124,25 @@ public struct Heap { * value; for a min-heap it is the minimum value. Performance: O(log n). */ @discardableResult public mutating func remove() -> T? { - if !nodes.isEmpty { - if nodes.count == 1 { - return nodes.removeLast() - } else { - // Use the last node to replace the first one, then fix the heap by - // shifting this new first node into its proper position. - let value = nodes[0] - nodes[0] = nodes.removeLast() - shiftDown(0) - return value - } + guard !nodes.isEmpty else { return nil } + + if nodes.count == 1 { + return nodes.removeLast() + } else { + // Use the last node to replace the first one, then fix the heap by + // shifting this new first node into its proper position. + let value = nodes[0] + nodes[0] = nodes.removeLast() + shiftDown(0) + return value } - return nil } /** * Removes an arbitrary node from the heap. Performance: O(log n). * Note that you need to know the node's index. */ - @discardableResult public mutating func removeAt(_ index: Int) -> T? { + @discardableResult public mutating func remove(at index: Int) -> T? { guard index < nodes.count else { return nil } let size = nodes.count - 1 @@ -165,7 +158,7 @@ public struct Heap { * Takes a child node and looks at its parents; if a parent is not larger * (max-heap) or not smaller (min-heap) than the child, we exchange them. */ - mutating func shiftUp(_ index: Int) { + internal mutating func shiftUp(_ index: Int) { var childIndex = index let child = nodes[childIndex] var parentIndex = self.parentIndex(ofIndex: childIndex) @@ -183,7 +176,7 @@ public struct Heap { * Looks at a parent node and makes sure it is still larger (max-heap) or * smaller (min-heap) than its childeren. */ - private mutating func shiftDown(from index: Int, until endIndex: Int) { + internal mutating func shiftDown(from index: Int, until endIndex: Int) { let leftChildIndex = self.leftChildIndex(ofIndex: index) let rightChildIndex = leftChildIndex + 1 @@ -204,7 +197,7 @@ public struct Heap { shiftDown(from: first, until: endIndex) } - private mutating func shiftDown(_ index: Int) { + internal mutating func shiftDown(_ index: Int) { shiftDown(from: index, until: nodes.count) } @@ -222,7 +215,7 @@ extension Heap where T: Equatable { /** Removes the first occurrence of a node from the heap. Performance: O(n log n). */ @discardableResult public mutating func remove(node: T) -> T? { if let index = index(of: node) { - return removeAt(index) + return remove(at: index) } return nil } diff --git a/Heap/Tests/HeapTests.swift b/Heap/Tests/HeapTests.swift index 36035fe93..1ed15c726 100755 --- a/Heap/Tests/HeapTests.swift +++ b/Heap/Tests/HeapTests.swift @@ -154,14 +154,14 @@ class HeapTests: XCTestCase { XCTAssertEqual(h4.peek()!, 0) } - func testCreateMaxHeapEqualElements() { + func testCreateMaxHeapEqualnodes() { let heap = Heap(array: [1, 1, 1, 1, 1], sort: >) XCTAssertTrue(verifyMaxHeap(heap)) XCTAssertTrue(verifyMinHeap(heap)) XCTAssertEqual(heap.nodes, [1, 1, 1, 1, 1]) } - func testCreateMinHeapEqualElements() { + func testCreateMinHeapEqualnodes() { let heap = Heap(array: [1, 1, 1, 1, 1], sort: <) XCTAssertTrue(verifyMinHeap(heap)) XCTAssertTrue(verifyMaxHeap(heap)) @@ -198,33 +198,33 @@ class HeapTests: XCTestCase { } } - func testRemovingAtIndex() { + func testRemoving() { var h = Heap(array: [100, 50, 70, 10, 20, 60, 65], sort: >) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 60, 65]) //test index out of bounds - let v = h.removeAt(10) + let v = h.remove(at: 10) XCTAssertEqual(v, nil) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 60, 65]) - let v1 = h.removeAt(5) + let v1 = h.remove(at: 5) XCTAssertEqual(v1, 60) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 65]) - let v2 = h.removeAt(4) + let v2 = h.remove(at: 4) XCTAssertEqual(v2, 20) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.nodes, [100, 65, 70, 10, 50]) - let v3 = h.removeAt(4) + let v3 = h.remove(at: 4) XCTAssertEqual(v3, 50) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.nodes, [100, 65, 70, 10]) - let v4 = h.removeAt(0) + let v4 = h.remove(at: 0) XCTAssertEqual(v4, 100) XCTAssertTrue(verifyMaxHeap(h)) XCTAssertEqual(h.nodes, [70, 65, 10]) @@ -267,17 +267,6 @@ class HeapTests: XCTestCase { XCTAssertEqual(h.nodes, [13, 12, 9, 5, 6, 8, 7, 4, 0, 1, 2]) } - func testRemoveNode() { - var h = Heap(array: [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1], sort: >) - XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertEqual(h.nodes, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1]) - XCTAssertEqual(h.node(at: 3)!, 5) - let v = h.remove(node: 5) - XCTAssertEqual(v, 5) - XCTAssertTrue(verifyMaxHeap(h)) - XCTAssertFalse(h.nodes.contains(5)) - } - func testRemoveRandomItems() { for n in 1...40 { var a = randomArray(n) @@ -288,16 +277,8 @@ class HeapTests: XCTestCase { let m = (n + 1)/2 for k in 1...m { let i = Int(arc4random_uniform(UInt32(n - k + 1))) - - var v: Int? = nil - if k == 2 || k == m { - v = h.remove(node: h.node(at: i)!) - } else { - v = h.removeAt(i) - } - XCTAssertNotNil(v) - - let j = a.index(of: v!)! + let v = h.remove(at: i)! + let j = a.index(of: v)! a.remove(at: j) XCTAssertTrue(verifyMaxHeap(h)) From 39b7311ec6fe68af0fb83b6322d7121a6d9c8f62 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 8 Jan 2018 17:47:10 -0800 Subject: [PATCH 040/327] Removes redundant `internal` modifier. --- Heap/Heap.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heap/Heap.swift b/Heap/Heap.swift index ae392d448..cf39fb8a5 100755 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -6,7 +6,7 @@ public struct Heap { /** The array that stores the heap's nodes. */ - internal var nodes = [T]() + var nodes = [T]() /** * Determines how to compare two nodes in the heap. From d4d471ba02dfcca3c58221a35159f650d15eb570 Mon Sep 17 00:00:00 2001 From: Keith Date: Wed, 10 Jan 2018 11:28:05 +0800 Subject: [PATCH 041/327] Update README.markdown fix Code syntax error --- Binary Search Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index 1d9321591..84e278f5c 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -268,7 +268,7 @@ If there are no more nodes to look at -- when `left` or `right` is nil -- then w Searching is a recursive process, but you can also implement it with a simple loop instead: ```swift - public func search(value: T) -> BinarySearchTree? { + public func search(_ value: T) -> BinarySearchTree? { var node: BinarySearchTree? = self while let n = node { if value < n.value { From adf606599050c8eaf4b63a0c8e18a5b52a4892b7 Mon Sep 17 00:00:00 2001 From: ck Date: Wed, 19 Jul 2017 15:47:40 -0700 Subject: [PATCH 042/327] Encode and Decode A Binary Tree Encode and Decode A Binary Tree --- .../Contents.swift | 49 +++++++++ .../Sources/EncodeAndDecodeTree.swift | 104 ++++++++++++++++++ .../contents.xcplayground | 4 + .../EncodeAndDecodeTree.swift | 104 ++++++++++++++++++ Encode and Decode Tree/readme.md | 27 +++++ .../contents.xcworkspacedata | 10 ++ 6 files changed, 298 insertions(+) create mode 100644 Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift create mode 100644 Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift create mode 100644 Encode and Decode Tree/EncodeAndDecodeTree.playground/contents.xcplayground create mode 100644 Encode and Decode Tree/EncodeAndDecodeTree.swift create mode 100644 Encode and Decode Tree/readme.md diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift new file mode 100644 index 000000000..dbd2fd180 --- /dev/null +++ b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift @@ -0,0 +1,49 @@ +//: Playground - noun: a place where people can play + + +func printTree(_ root: TreeNode?) { + guard let root = root else { + return + } + + var pointer = root + + let leftVal = root.left == nil ? "nil" : root.left!.val + let rightVal = root.right == nil ? "nil" : root.right!.val + + print("val: \(root.val) left: \(leftVal) right: \(rightVal)") + + printTree(root.left) + printTree(root.right) +} + +let s = EncodeAndDecodeTree() + +let node1 = TreeNode("a") +let node2 = TreeNode("b") +let node3 = TreeNode("c") +let node4 = TreeNode("d") +let node5 = TreeNode("e") + +node1.left = node2 +node1.right = node3 +node3.left = node4 +node3.right = node5 + +let encodeStr = s.encode(node1) +print(encodeStr) +// "a b # # c d # # e # #" + + +let root = s.decode(encodeStr) +print("Tree:") +printTree(root) +/* + Tree: + val: a left: b right: c + val: b left: nil right: nil + val: c left: d right: e + val: d left: nil right: nil + val: e left: nil right: nil + */ + diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift new file mode 100644 index 000000000..e9d22f8a9 --- /dev/null +++ b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift @@ -0,0 +1,104 @@ +// +// EncodeAndDecodeTree.swift +// +// +// Created by Kai Chen on 19/07/2017. +// +// + +import Foundation + +public class TreeNode { + public var val: String + public var left: TreeNode? + public var right: TreeNode? + + public init(_ val: String, left: TreeNode? = nil, right: TreeNode? = nil) { + self.val = val + self.left = left + self.right = right + } +} + +public class EncodeAndDecodeTree { + private var encodeStr = "" + private var ret: [String] = [] + + public init() {} + + public func encode(_ root: TreeNode?) -> String { + encodeIt(root) + + return encodeStr + } + + public func decode(_ data: String) -> TreeNode? { + var s = data + while (s.contains(" ")) { + let index = s.index(of: " ") + let endIndex = s.index(before: index) + let element = s[s.startIndex...endIndex] + ret.append(element) + let range = ClosedRange(uncheckedBounds: (lower: s.startIndex, upper: index)) + s.removeSubrange(range) + } + + if ret.count == 0 { + return nil + } + + var dep = 0 + let root = decodeIt(&dep) + + return root + } + + private func getNode(_ element: String) -> TreeNode? { + if element == "#" { + return nil + } + + return TreeNode(element) + } + + private func decodeIt(_ dep: inout Int) -> TreeNode? { + guard let currentNode = getNode(ret[dep]) else { + return nil + } + + dep += 1 + let left = decodeIt(&dep) + dep += 1 + let right = decodeIt(&dep) + + currentNode.left = left + currentNode.right = right + + return currentNode + } + + private func encodeIt(_ root: TreeNode?) { + guard let root = root else { + encodeStr += "# " + return + } + + encodeStr += root.val + " " + encodeIt(root.left) + encodeIt(root.right) + } +} + +extension String { + func index(of target: Character) -> String.Index { + var i = 0 + for c in self.characters { + if c == target { + return self.index(self.startIndex, offsetBy: i) + } + i += 1 + } + + return self.endIndex + } +} diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.playground/contents.xcplayground b/Encode and Decode Tree/EncodeAndDecodeTree.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Encode and Decode Tree/EncodeAndDecodeTree.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.swift b/Encode and Decode Tree/EncodeAndDecodeTree.swift new file mode 100644 index 000000000..daa3c3ea2 --- /dev/null +++ b/Encode and Decode Tree/EncodeAndDecodeTree.swift @@ -0,0 +1,104 @@ +// +// EncodeAndDecodeTree.swift +// +// +// Created by Kai Chen on 19/07/2017. +// +// + +import Foundation + +public class TreeNode { + public var val: String + public var left: TreeNode? + public var right: TreeNode? + + public init(_ val: String, left: TreeNode? = nil, right: TreeNode? = nil) { + self.val = val + self.left = left + self.right = right + } +} + +public class EncodeAndDecodeTree { + private var encodeStr = "" + private var ret: [String] = [] + + public init() {} + + public func encode(_ root: TreeNode?) -> String { + encodeIt(root) + + return encodeStr + } + + public func decode(_ data: String) -> TreeNode? { + var s = data + while (s.contains(" ")) { + let index = s.index(of: " ") + let endIndex = s.index(before: index) + let element = s[s.startIndex...endIndex] + ret.append(element) + let range = ClosedRange(uncheckedBounds: (lower: s.startIndex, upper: index)) + s.removeSubrange(range) + } + + if ret.count == 0 { + return nil + } + + var dep = 0 + let root = decodeIt(&dep) + + return root + } + + private func getNode(_ element: String) -> TreeNode? { + if element == "#" { + return nil + } + + return TreeNode(element) + } + + private func decodeIt(_ dep: inout Int) -> TreeNode? { + guard let currentNode = getNode(ret[dep]) else { + return nil + } + + dep += 1 + let left = decodeIt(&dep) + dep += 1 + let right = decodeIt(&dep) + + currentNode.left = left + currentNode.right = right + + return currentNode + } + + private func encodeIt(_ root: TreeNode?) { + guard let root = root else { + encodeStr += "# " + return + } + + encodeStr += root.val + " " + encodeIt(root.left) + encodeIt(root.right) + } +} + +extension String { + func index(of target: Character) -> String.Index { + var i = 0 + for c in self.characters { + if c == target { + return self.index(self.startIndex, offsetBy: i) + } + i += 1 + } + + return self.endIndex + } +} diff --git a/Encode and Decode Tree/readme.md b/Encode and Decode Tree/readme.md new file mode 100644 index 000000000..c986d9147 --- /dev/null +++ b/Encode and Decode Tree/readme.md @@ -0,0 +1,27 @@ +# Encode and Decode Binary Tree + +We need to design an algorithm to encode and decode a binary tree. +* **Encode**: Convert a tree into a string that can be stored in the disk. +* **Decode**: Given the encoded string, you need to convert it into a Tree. + +For example, you may serialize the following tree + + +as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself. +Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless. + +## Solution +For example, given a tree like this +> a +> / \\ +> +> b c +> +> ​ / \\ +> ​ d e + +We can use inorder traversal to convert the tree into the string like this `a b # # c d # # e # #` + +So, the idea is for the empty node, we use `#` to represent. + +For the decode process, we can still use inorder to convert the string back to a tree. \ No newline at end of file diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 4cab8e2d4..77f124fc3 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -117,6 +117,16 @@ location = "group:LRU Cache/Readme.md">
    + + + + + + From f5c74b9aa9f34e7e57fc16059ee3076642abcdc9 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 16 Nov 2017 09:13:20 -0800 Subject: [PATCH 043/327] Refactor in progress --- Encode and Decode Tree/readme.md | 58 ++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/Encode and Decode Tree/readme.md b/Encode and Decode Tree/readme.md index c986d9147..7f3e5538d 100644 --- a/Encode and Decode Tree/readme.md +++ b/Encode and Decode Tree/readme.md @@ -1,27 +1,49 @@ # Encode and Decode Binary Tree -We need to design an algorithm to encode and decode a binary tree. -* **Encode**: Convert a tree into a string that can be stored in the disk. -* **Decode**: Given the encoded string, you need to convert it into a Tree. +> **Note**: The prerequisite for this article is an understanding of how [binary trees](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Binary%20Tree) work. -For example, you may serialize the following tree +Trees are complex structures. Unlike linear collections such as arrays or linked lists, trees are *non-linear* and each element in a tree has positional information such as the *parent-child* relationship between nodes. When you want to send a tree structure to your backend, you need to send the data of each node, and a way to represent the parent-child relationship for each node. +Your strategy in how you choose to represent this information is called your **encoding** strategy. The opposite of that - changing your encoded data back to its original form - is your **decoding** strategy. -as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself. -Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless. +There are many ways to encode a tree and decode a tree. The important thing to keep in mind is that encoding and decoding strategies are closely related. The way you choose to encode a tree directly affects how you might decode a tree. -## Solution -For example, given a tree like this -> a -> / \\ -> -> b c -> -> ​ / \\ -> ​ d e +Encoding and decoding are synonyms to *serializing* and *deserializing* trees. -We can use inorder traversal to convert the tree into the string like this `a b # # c d # # e # #` +As a reference, the following code represents the typical `Node` type of a binary tree: -So, the idea is for the empty node, we use `#` to represent. +```swift +class BinaryNode { + var data: Element + var leftChild: BinaryNode? + var rightChild: BinaryNode? + + // ... (rest of the implementation) +} +``` + +## Encoding + +As mentioned before, there are different ways to do encoding. For no particular reason, you'll opt for the following rules: + +1. The result of the encoding will be a `String` object. +2. You'll encode using *pre-order* traversal. + +Here's an example of this operation in code: + +```swift +extension BinaryNode { + var encodedString: String { + var str = "" + preOrderTraversal { str.append($0) } + return str + } + + func preOrderTraversal(visit: (T) -> ()) { + visit(data) + leftChild?.preOrderTraversal(visit: visit) + rightChild?.preOrderTraversal(visit: visit) + } +} +``` -For the decode process, we can still use inorder to convert the string back to a tree. \ No newline at end of file From b772141951fe32729c6976d9a082b5c2f3eef203 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 16 Nov 2017 10:06:14 -0800 Subject: [PATCH 044/327] More progress --- Encode and Decode Tree/readme.md | 77 ++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/Encode and Decode Tree/readme.md b/Encode and Decode Tree/readme.md index 7f3e5538d..3b2281224 100644 --- a/Encode and Decode Tree/readme.md +++ b/Encode and Decode Tree/readme.md @@ -33,17 +33,86 @@ Here's an example of this operation in code: ```swift extension BinaryNode { + // 1 + private var splitter: String { return "," } + private var nilNode: String { return "nil" } + + // 2 var encodedString: String { var str = "" - preOrderTraversal { str.append($0) } + preOrderTraversal { data in + if let data = data { + let string = String(describing: data) + str.append(string) + } else { + str.append(nilNode) + } + str.append(splitter) + } return str } - func preOrderTraversal(visit: (T) -> ()) { + // 3 + func preOrderTraversal(visit: (T?) -> ()) { visit(data) - leftChild?.preOrderTraversal(visit: visit) - rightChild?.preOrderTraversal(visit: visit) + + if let leftChild = leftChild { + leftChild.preOrderTraversal(visit: visit) + } else { + visit(nil) + } + + if let rightChild = rightChild { + rightChild.preOrderTraversal(visit: visit) + } else { + visit(nil) + } } } ``` +Here's a high level overview of the above code: + +1. `splitter` is a way to distinguish the nodes in a string. To illustrate its importance, consider the following encoded string "banana". How did the tree structure look like before encoding? Without the `splitter`, you can't tell. + +2. `encodedString` is the result of the encoding process. Returns a string representation of the tree. For example: "ba,nana,nil" represents a tree with two nodes - "ba" and "nana" - in pre-order format. + +3. It is interesting to note that this pre-order traversal implementation also emits `nil` values in place of absent children. + +## Decoding + +Your decoding strategy is the exact opposite of your encoding strategy. You'll take an encoded string, and turn it back into your binary tree. + +Your encoding strategy followed the following rules: + +1. The result of the encoding will be a `String` object. +2. You'll encode using *pre-order* traversal. + +The implementation also added a few important details: + +* node values are separated by `,` +* `nil` children are denoted by the `nil` string + +These details will shape your `decode` operation. Here's a possible implementation: + +```swift +extension BinaryTree { + + static func decode(from string: String) -> BinaryNode? { +    let array = string.split(separator: ",") + let deque: Deque = array + return decode(from: deque) + } + + static func decode(from deque: RangeReplaceableCollection) + -> BinaryNode? { + + } +} +``` + + + + + + From 959aaafe2d16b9e82f830381c6856c396590c51f Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 16 Nov 2017 10:22:28 -0800 Subject: [PATCH 045/327] More progress. --- Encode and Decode Tree/readme.md | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Encode and Decode Tree/readme.md b/Encode and Decode Tree/readme.md index 3b2281224..506bfbe05 100644 --- a/Encode and Decode Tree/readme.md +++ b/Encode and Decode Tree/readme.md @@ -34,8 +34,8 @@ Here's an example of this operation in code: ```swift extension BinaryNode { // 1 - private var splitter: String { return "," } - private var nilNode: String { return "nil" } + fileprivate var splitter: String { return "," } + fileprivate var nilNode: String { return "nil" } // 2 var encodedString: String { @@ -98,19 +98,32 @@ These details will shape your `decode` operation. Here's a possible implementati ```swift extension BinaryTree { + // 1 static func decode(from string: String) -> BinaryNode? {    let array = string.split(separator: ",") - let deque: Deque = array - return decode(from: deque) + return decode(from: array) } - static func decode(from deque: RangeReplaceableCollection) + // 2 + static func decode(from sequence: Sequence) -> BinaryNode? { + guard let value = sequence.first else { return nil } + if value == nilNode { + return nil + } else { + let node = BinaryNode(value: value) + node.leftChild = decode(from: AnySequence(sequence.dropFirst())) + node.rightChild = decode(from: AnySequence(sequence.dropFirst())) + } } } ``` +Here's a high level overview of the above code: + +1. Takes a `String`, and uses `split` to partition the contents of `string` into an array based on the `","` character. +2. Takes any `Sequence` type and recursively creates a binary tree based on the rules declared in the encoding operation. From e1599029f885de746bb8b7626246d57f7bdbd664 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 18 Nov 2017 01:45:12 -0800 Subject: [PATCH 046/327] More progress --- Encode and Decode Tree/readme.md | 60 +++++++++++++++++--------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/Encode and Decode Tree/readme.md b/Encode and Decode Tree/readme.md index 506bfbe05..e0c38531c 100644 --- a/Encode and Decode Tree/readme.md +++ b/Encode and Decode Tree/readme.md @@ -34,8 +34,8 @@ Here's an example of this operation in code: ```swift extension BinaryNode { // 1 - fileprivate var splitter: String { return "," } - fileprivate var nilNode: String { return "nil" } + fileprivate var separator: String { return "," } + fileprivate var nilNode: String { return "X" } // 2 var encodedString: String { @@ -47,25 +47,25 @@ extension BinaryNode { } else { str.append(nilNode) } - str.append(splitter) + str.append(separator) } return str } // 3 - func preOrderTraversal(visit: (T?) -> ()) { - visit(data) + func preOrderTraversal(visit: (Element?) throws -> ()) rethrows { + try visit(data) if let leftChild = leftChild { - leftChild.preOrderTraversal(visit: visit) + try leftChild.preOrderTraversal(visit: visit) } else { - visit(nil) + try visit(nil) } if let rightChild = rightChild { - rightChild.preOrderTraversal(visit: visit) + try rightChild.preOrderTraversal(visit: visit) } else { - visit(nil) + try visit(nil) } } } @@ -73,7 +73,7 @@ extension BinaryNode { Here's a high level overview of the above code: -1. `splitter` is a way to distinguish the nodes in a string. To illustrate its importance, consider the following encoded string "banana". How did the tree structure look like before encoding? Without the `splitter`, you can't tell. +1. `separator` is a way to distinguish the nodes in a string. To illustrate its importance, consider the following encoded string "banana". How did the tree structure look like before encoding? Without the `separator`, you can't tell. 2. `encodedString` is the result of the encoding process. Returns a string representation of the tree. For example: "ba,nana,nil" represents a tree with two nodes - "ba" and "nana" - in pre-order format. @@ -96,34 +96,36 @@ The implementation also added a few important details: These details will shape your `decode` operation. Here's a possible implementation: ```swift -extension BinaryTree { - +extension BinaryNode { + // 1 - static func decode(from string: String) -> BinaryNode? { -    let array = string.split(separator: ",") - return decode(from: array) + public static func decode(from str: String) -> AVLNode? { + let components = encoded.lazy.split(separator: separator).reversed().map(String.init) + return decode(from: components) } - - // 2 - static func decode(from sequence: Sequence) - -> BinaryNode? { + + public static func decode(from array: inout [String]) + -> AVLNode? { - guard let value = sequence.first else { return nil } - if value == nilNode { - return nil - } else { - let node = BinaryNode(value: value) - node.leftChild = decode(from: AnySequence(sequence.dropFirst())) - node.rightChild = decode(from: AnySequence(sequence.dropFirst())) - } + guard !array.isEmpty else { return nil } + let value = array.removeLast() + guard value != "\(nilNode)" else { return nil } + + let node = AVLNode(value: value) + node.leftChild = decode(from: &array) + node.rightChild = decode(from: &array) + return node } } ``` Here's a high level overview of the above code: -1. Takes a `String`, and uses `split` to partition the contents of `string` into an array based on the `","` character. -2. Takes any `Sequence` type and recursively creates a binary tree based on the rules declared in the encoding operation. +1. Takes a `String`, and uses `split` to partition the contents of `string` into an array based on the `separator` defined in the encoding step. The result is first `reversed`, and then mapped to a `String`. The `reverse` step is an optimization for the next function, allowing us to use `array.removeLast()` instead of `array.removeFirst()`. + +2. Using an array as a stack, you recursively decode each node. The array keeps track of sequence of nodes and progress. + + From 8bc6ab70c45d36d55466046d613509f64ca8ee59 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 18 Nov 2017 01:51:20 -0800 Subject: [PATCH 047/327] Added example case. --- Encode and Decode Tree/readme.md | 42 ++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/Encode and Decode Tree/readme.md b/Encode and Decode Tree/readme.md index e0c38531c..d7dd89424 100644 --- a/Encode and Decode Tree/readme.md +++ b/Encode and Decode Tree/readme.md @@ -125,9 +125,47 @@ Here's a high level overview of the above code: 2. Using an array as a stack, you recursively decode each node. The array keeps track of sequence of nodes and progress. +Here's an example output of a tree undergoing the encoding and decoding process: - - +``` +Original Tree + + ┌──8423 + ┌──8391 + │ └──nil +┌──7838 +│ │ ┌──4936 +│ └──3924 +│ └──2506 +830 +│ ┌──701 +└──202 + └──169 + +Encoded tree: 830,202,169,X,X,701,X,X,7838,3924,2506,X,X,4936,X,X,8391,X,8423,X,X, + +Decoded tree + + ┌──8423 + ┌──8391 + │ └──nil +┌──7838 +│ │ ┌──4936 +│ └──3924 +│ └──2506 +830 +│ ┌──701 +└──202 + └──169 + ``` + +Notice the original tree and decoded tree are identical. + +## Further Reading & References + +- [LeetCode](https://leetcode.com/problems/serialize-and-deserialize-binary-tree/description/) + +*Written for the Swift Algorithm Club by Kai Chen & Kelvin Lau* From eeea2027fe024dcf7a553f6c3c3479e39942045f Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 21 Nov 2017 22:32:03 -0800 Subject: [PATCH 048/327] Updates readme to reference new class to handle encoding and decoding operations --- Encode and Decode Tree/readme.md | 103 +++++++++++++++++++------------ 1 file changed, 65 insertions(+), 38 deletions(-) diff --git a/Encode and Decode Tree/readme.md b/Encode and Decode Tree/readme.md index d7dd89424..d60075e63 100644 --- a/Encode and Decode Tree/readme.md +++ b/Encode and Decode Tree/readme.md @@ -13,7 +13,7 @@ Encoding and decoding are synonyms to *serializing* and *deserializing* trees. As a reference, the following code represents the typical `Node` type of a binary tree: ```swift -class BinaryNode { +class BinaryNode { var data: Element var leftChild: BinaryNode? var rightChild: BinaryNode? @@ -22,6 +22,24 @@ class BinaryNode { } ``` +Your encoding and decoding methods will reside in the `BinaryNodeEncoder` and `BinaryNodeDecoder` classes: + +```swift +class BinaryNodeCoder { + + // transforms nodes into string representation + func encode(_ node: BinaryNode) throws -> String where T: Encodable { + + } + + // transforms string into `BinaryNode` representation + func decode(_ node: BinaryNodeType, from string: String) + throws -> BinaryNode where T: Decodable { + + } +} +``` + ## Encoding As mentioned before, there are different ways to do encoding. For no particular reason, you'll opt for the following rules: @@ -32,27 +50,9 @@ As mentioned before, there are different ways to do encoding. For no particular Here's an example of this operation in code: ```swift -extension BinaryNode { - // 1 - fileprivate var separator: String { return "," } - fileprivate var nilNode: String { return "X" } - - // 2 - var encodedString: String { - var str = "" - preOrderTraversal { data in - if let data = data { - let string = String(describing: data) - str.append(string) - } else { - str.append(nilNode) - } - str.append(separator) - } - return str - } +fileprivate extension BinaryNode { - // 3 + // 1 func preOrderTraversal(visit: (Element?) throws -> ()) rethrows { try visit(data) @@ -69,15 +69,41 @@ extension BinaryNode { } } } + +class BinaryNodeCoder { + + // 2 + private var separator: String { return "," } + + // 3 + private var nilNode: String { return "X" } + + // 4 + func encode(_ node: BinaryNode) -> String { + var str = "" + node.preOrderTraversal { data in + if let data = data { + let string = String(describing: data) + str.append(string) + } else { + str.append(nilNode) + } + str.append(separator) + } + return str + } + + // ... +} ``` Here's a high level overview of the above code: -1. `separator` is a way to distinguish the nodes in a string. To illustrate its importance, consider the following encoded string "banana". How did the tree structure look like before encoding? Without the `separator`, you can't tell. +2. `separator` is a way to distinguish the nodes in a string. To illustrate its importance, consider the following encoded string "banana". How did the tree structure look like before encoding? Without the `separator`, you can't tell. -2. `encodedString` is the result of the encoding process. Returns a string representation of the tree. For example: "ba,nana,nil" represents a tree with two nodes - "ba" and "nana" - in pre-order format. +3. `nilNode` is used to identify empty children. This a necesssary piece of information to retain in order to rebuild the tree later. -3. It is interesting to note that this pre-order traversal implementation also emits `nil` values in place of absent children. +4. `encode` returns a `String` representation of the `BinaryNode`. For example: "ba,nana,nil" represents a tree with two nodes - "ba" and "nana" - in pre-order format. ## Decoding @@ -96,28 +122,29 @@ The implementation also added a few important details: These details will shape your `decode` operation. Here's a possible implementation: ```swift -extension BinaryNode { +class BinaryNodeCoder { + + // ... + // 1 - public static func decode(from str: String) -> AVLNode? { + func decode(_ string: String) -> BinaryNode? { let components = encoded.lazy.split(separator: separator).reversed().map(String.init) return decode(from: components) } - - public static func decode(from array: inout [String]) - -> AVLNode? { + + // 2 + private func decode(from array: inout [String]) -> AVLNode? { + guard !array.isEmpty else { return nil } + let value = array.removeLast() + guard value != "\(nilNode)" else { return nil } - guard !array.isEmpty else { return nil } - let value = array.removeLast() - guard value != "\(nilNode)" else { return nil } - - let node = AVLNode(value: value) - node.leftChild = decode(from: &array) - node.rightChild = decode(from: &array) - return node + let node = AVLNode(value: value) + node.leftChild = decode(from: &array) + node.rightChild = decode(from: &array) + return node } } -``` Here's a high level overview of the above code: From 4187a9af9f6b316479562589fd78c7685b633f22 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 23 Nov 2017 01:54:56 -0800 Subject: [PATCH 049/327] Fixed some formatting. --- Encode and Decode Tree/readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Encode and Decode Tree/readme.md b/Encode and Decode Tree/readme.md index d60075e63..ce5b45aaf 100644 --- a/Encode and Decode Tree/readme.md +++ b/Encode and Decode Tree/readme.md @@ -33,7 +33,7 @@ class BinaryNodeCoder { } // transforms string into `BinaryNode` representation - func decode(_ node: BinaryNodeType, from string: String) + func decode(from string: String) throws -> BinaryNode where T: Decodable { } @@ -145,6 +145,7 @@ class BinaryNodeCoder { return node } } +``` Here's a high level overview of the above code: From 25e6a190af8d13ee4e72bd41087fe593d49eba0f Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 23 Nov 2017 23:34:24 -0800 Subject: [PATCH 050/327] Removed mentions of Encodable and Decodable protocol. Fixed a typo. --- Encode and Decode Tree/readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Encode and Decode Tree/readme.md b/Encode and Decode Tree/readme.md index ce5b45aaf..b60e0a504 100644 --- a/Encode and Decode Tree/readme.md +++ b/Encode and Decode Tree/readme.md @@ -13,7 +13,7 @@ Encoding and decoding are synonyms to *serializing* and *deserializing* trees. As a reference, the following code represents the typical `Node` type of a binary tree: ```swift -class BinaryNode { +class BinaryNode { var data: Element var leftChild: BinaryNode? var rightChild: BinaryNode? @@ -79,7 +79,7 @@ class BinaryNodeCoder { private var nilNode: String { return "X" } // 4 - func encode(_ node: BinaryNode) -> String { + func encode(_ node: BinaryNode) -> String { var str = "" node.preOrderTraversal { data in if let data = data { @@ -128,13 +128,13 @@ class BinaryNodeCoder { // ... // 1 - func decode(_ string: String) -> BinaryNode? { + func decode(_ string: String) -> BinaryNode? { let components = encoded.lazy.split(separator: separator).reversed().map(String.init) return decode(from: components) } // 2 - private func decode(from array: inout [String]) -> AVLNode? { + private func decode(from array: inout [String]) -> BinaryNode? { guard !array.isEmpty else { return nil } let value = array.removeLast() guard value != "\(nilNode)" else { return nil } From 074dac29084d235f93edb68e58d2deb92ffc0bbf Mon Sep 17 00:00:00 2001 From: ck Date: Sun, 14 Jan 2018 18:16:35 -0800 Subject: [PATCH 051/327] Address comments and update the code to sync up with readme --- .../Contents.swift | 21 ++- .../Sources/EncodeAndDecodeTree.swift | 137 ++++++++---------- .../EncodeAndDecodeTree.swift | 137 ++++++++---------- 3 files changed, 137 insertions(+), 158 deletions(-) diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift index dbd2fd180..44c2440d5 100644 --- a/Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift +++ b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Contents.swift @@ -1,13 +1,10 @@ //: Playground - noun: a place where people can play - -func printTree(_ root: TreeNode?) { +func printTree(_ root: BinaryNode?) { guard let root = root else { return } - var pointer = root - let leftVal = root.left == nil ? "nil" : root.left!.val let rightVal = root.right == nil ? "nil" : root.right!.val @@ -17,25 +14,25 @@ func printTree(_ root: TreeNode?) { printTree(root.right) } -let s = EncodeAndDecodeTree() +let coder = BinaryNodeCoder() -let node1 = TreeNode("a") -let node2 = TreeNode("b") -let node3 = TreeNode("c") -let node4 = TreeNode("d") -let node5 = TreeNode("e") +let node1 = BinaryNode("a") +let node2 = BinaryNode("b") +let node3 = BinaryNode("c") +let node4 = BinaryNode("d") +let node5 = BinaryNode("e") node1.left = node2 node1.right = node3 node3.left = node4 node3.right = node5 -let encodeStr = s.encode(node1) +let encodeStr = try coder.encode(node1) print(encodeStr) // "a b # # c d # # e # #" -let root = s.decode(encodeStr) +let root: BinaryNode = coder.decode(from: encodeStr)! print("Tree:") printTree(root) /* diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift index e9d22f8a9..10bb277f5 100644 --- a/Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift +++ b/Encode and Decode Tree/EncodeAndDecodeTree.playground/Sources/EncodeAndDecodeTree.swift @@ -8,97 +8,88 @@ import Foundation -public class TreeNode { - public var val: String - public var left: TreeNode? - public var right: TreeNode? - - public init(_ val: String, left: TreeNode? = nil, right: TreeNode? = nil) { - self.val = val - self.left = left - self.right = right - } +protocol BinaryNodeEncoder { + func encode(_ node: BinaryNode?) throws -> String } -public class EncodeAndDecodeTree { - private var encodeStr = "" - private var ret: [String] = [] +protocol BinaryNodeDecoder { + func decode(from string: String) -> BinaryNode? +} - public init() {} +public class BinaryNodeCoder: BinaryNodeEncoder, BinaryNodeDecoder { - public func encode(_ root: TreeNode?) -> String { - encodeIt(root) + // MARK: Private - return encodeStr - } + private let separator: Character = "," + private let nilNode = "X" - public func decode(_ data: String) -> TreeNode? { - var s = data - while (s.contains(" ")) { - let index = s.index(of: " ") - let endIndex = s.index(before: index) - let element = s[s.startIndex...endIndex] - ret.append(element) - let range = ClosedRange(uncheckedBounds: (lower: s.startIndex, upper: index)) - s.removeSubrange(range) - } - - if ret.count == 0 { - return nil - } - - var dep = 0 - let root = decodeIt(&dep) - - return root + private func decode(from array: inout [String]) -> BinaryNode? { + guard !array.isEmpty else { + return nil } - private func getNode(_ element: String) -> TreeNode? { - if element == "#" { - return nil - } + let value = array.removeLast() - return TreeNode(element) + guard value != nilNode, let val = value as? T else { + return nil } - private func decodeIt(_ dep: inout Int) -> TreeNode? { - guard let currentNode = getNode(ret[dep]) else { - return nil - } + let node = BinaryNode(val) + node.left = decode(from: &array) + node.right = decode(from: &array) - dep += 1 - let left = decodeIt(&dep) - dep += 1 - let right = decodeIt(&dep) + return node + } - currentNode.left = left - currentNode.right = right + // MARK: Public - return currentNode + public init() {} + + public func encode(_ node: BinaryNode?) throws -> String { + var str = "" + node?.preOrderTraversal { data in + if let data = data { + let string = String(describing: data) + str.append(string) + } else { + str.append(nilNode) + } + str.append(separator) } - private func encodeIt(_ root: TreeNode?) { - guard let root = root else { - encodeStr += "# " - return - } + return str + } - encodeStr += root.val + " " - encodeIt(root.left) - encodeIt(root.right) - } + public func decode(from string: String) -> BinaryNode? { + var components = string.split(separator: separator).reversed().map(String.init) + return decode(from: &components) + } } -extension String { - func index(of target: Character) -> String.Index { - var i = 0 - for c in self.characters { - if c == target { - return self.index(self.startIndex, offsetBy: i) - } - i += 1 - } - - return self.endIndex +public class BinaryNode { + public var val: Element + public var left: BinaryNode? + public var right: BinaryNode? + + public init(_ val: Element, left: BinaryNode? = nil, right: BinaryNode? = nil) { + self.val = val + self.left = left + self.right = right + } + + public func preOrderTraversal(visit: (Element?) throws -> ()) rethrows { + try visit(val) + + if let left = left { + try left.preOrderTraversal(visit: visit) + } else { + try visit(nil) + } + + if let right = right { + try right.preOrderTraversal(visit: visit) + } else { + try visit(nil) } + } } diff --git a/Encode and Decode Tree/EncodeAndDecodeTree.swift b/Encode and Decode Tree/EncodeAndDecodeTree.swift index daa3c3ea2..6ec8a3046 100644 --- a/Encode and Decode Tree/EncodeAndDecodeTree.swift +++ b/Encode and Decode Tree/EncodeAndDecodeTree.swift @@ -8,97 +8,88 @@ import Foundation -public class TreeNode { - public var val: String - public var left: TreeNode? - public var right: TreeNode? - - public init(_ val: String, left: TreeNode? = nil, right: TreeNode? = nil) { - self.val = val - self.left = left - self.right = right - } +protocol BinaryNodeEncoder { + func encode(_ node: BinaryNode?) throws -> String } -public class EncodeAndDecodeTree { - private var encodeStr = "" - private var ret: [String] = [] +protocol BinaryNodeDecoder { + func decode(from string: String) -> BinaryNode? +} - public init() {} +public class BinaryNodeCoder: BinaryNodeEncoder, BinaryNodeDecoder { - public func encode(_ root: TreeNode?) -> String { - encodeIt(root) + // MARK: Private - return encodeStr - } + private let separator: Character = "," + private let nilNode = "X" - public func decode(_ data: String) -> TreeNode? { - var s = data - while (s.contains(" ")) { - let index = s.index(of: " ") - let endIndex = s.index(before: index) - let element = s[s.startIndex...endIndex] - ret.append(element) - let range = ClosedRange(uncheckedBounds: (lower: s.startIndex, upper: index)) - s.removeSubrange(range) - } - - if ret.count == 0 { - return nil - } - - var dep = 0 - let root = decodeIt(&dep) - - return root + private func decode(from array: inout [String]) -> BinaryNode? { + guard !array.isEmpty else { + return nil } - private func getNode(_ element: String) -> TreeNode? { - if element == "#" { - return nil - } + let value = array.removeLast() - return TreeNode(element) + guard value != nilNode, let val = value as? T else { + return nil } - private func decodeIt(_ dep: inout Int) -> TreeNode? { - guard let currentNode = getNode(ret[dep]) else { - return nil - } + let node = BinaryNode(val) + node.left = decode(from: &array) + node.right = decode(from: &array) - dep += 1 - let left = decodeIt(&dep) - dep += 1 - let right = decodeIt(&dep) + return node + } - currentNode.left = left - currentNode.right = right + // MARK: Public - return currentNode + public init() {} + + public func encode(_ node: BinaryNode?) throws -> String { + var str = "" + node?.preOrderTraversal { data in + if let data = data { + let string = String(describing: data) + str.append(string) + } else { + str.append(nilNode) + } + str.append(separator) } - private func encodeIt(_ root: TreeNode?) { - guard let root = root else { - encodeStr += "# " - return - } + return str + } - encodeStr += root.val + " " - encodeIt(root.left) - encodeIt(root.right) - } + public func decode(from string: String) -> BinaryNode? { + var components = string.split(separator: separator).reversed().map(String.init) + return decode(from: &components) + } } -extension String { - func index(of target: Character) -> String.Index { - var i = 0 - for c in self.characters { - if c == target { - return self.index(self.startIndex, offsetBy: i) - } - i += 1 - } - - return self.endIndex +public class BinaryNode { + public var val: Element + public var left: BinaryNode? + public var right: BinaryNode? + + public init(_ val: Element, left: BinaryNode? = nil, right: BinaryNode? = nil) { + self.val = val + self.left = left + self.right = right + } + + public func preOrderTraversal(visit: (Element?) throws -> ()) rethrows { + try visit(val) + + if let left = left { + try left.preOrderTraversal(visit: visit) + } else { + try visit(nil) + } + + if let right = right { + try right.preOrderTraversal(visit: visit) + } else { + try visit(nil) } + } } From 90ac6b3b8cc3b341bc3e691998dc02a2cfd9de18 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 22 Jan 2018 08:09:08 -0800 Subject: [PATCH 052/327] Updates link to new contribution --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 7c9482d0c..6169b07b1 100644 --- a/README.markdown +++ b/README.markdown @@ -200,6 +200,7 @@ A lot of software developer interview questions consist of algorithmic puzzles. - [Finding Palindromes](Palindromes/) - [Dining Philosophers](DiningPhilosophers/) - [Egg Drop Problem](Egg%20Drop%20Problem/) +- [Encoding and Decoding Binary Tree](Encode%20and%20Decode%20Tree/) ## Learn more! For more information, check out these great books: From 5ff583027979d8826d2a9328f84534a1e5712323 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 26 Jan 2018 10:54:10 -0800 Subject: [PATCH 053/327] Fix typo: bottom-left -> bottom-right --- Longest Common Subsequence/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Longest Common Subsequence/README.markdown b/Longest Common Subsequence/README.markdown index 4cd2c2fcb..a62c562a6 100644 --- a/Longest Common Subsequence/README.markdown +++ b/Longest Common Subsequence/README.markdown @@ -99,7 +99,7 @@ And so on... this is how `lcsLength(_:)` fills in the entire matrix. ## Backtracking to find the actual subsequence -So far we've calculated the length of every possible subsequence. The length of the longest subsequence is found in the bottom-left corner of matrix, at `matrix[n+1][m+1]`. In the above example it is 4, so the LCS consists of 4 characters. +So far we've calculated the length of every possible subsequence. The length of the longest subsequence is found in the bottom-right corner of matrix, at `matrix[n+1][m+1]`. In the above example it is 4, so the LCS consists of 4 characters. Having the length of every combination of substrings makes it possible to determine *which* characters are part of the LCS itself by using a backtracking strategy. From 157431e2a6f5615a70495c045d6f21a1f86d4f14 Mon Sep 17 00:00:00 2001 From: Keith Date: Sun, 28 Jan 2018 07:06:45 +0800 Subject: [PATCH 054/327] Update README.markdown Find a kth smallest element should use a[k-1] --- Kth Largest Element/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kth Largest Element/README.markdown b/Kth Largest Element/README.markdown index aba2d9c29..f1721df96 100644 --- a/Kth Largest Element/README.markdown +++ b/Kth Largest Element/README.markdown @@ -40,7 +40,7 @@ Now, all we must do is take the value at index `a.count - k`: a[a.count - k] = a[8 - 4] = a[4] = 9 ``` -Of course, if you were looking for the k-th *smallest* element, you'd use `a[k]`. +Of course, if you were looking for the k-th *smallest* element, you'd use `a[k-1]`. ## A faster solution From e14a46f35964c4d1c0d41a90fd7b1ddbda5ad0bd Mon Sep 17 00:00:00 2001 From: Keith Date: Mon, 29 Jan 2018 09:04:10 +0800 Subject: [PATCH 055/327] Update README.markdown update the code in the article same as source code --- Kth Largest Element/README.markdown | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Kth Largest Element/README.markdown b/Kth Largest Element/README.markdown index f1721df96..b23d22b74 100644 --- a/Kth Largest Element/README.markdown +++ b/Kth Largest Element/README.markdown @@ -84,29 +84,29 @@ The index of pivot `9` is 4, and that's exactly the *k* we're looking for. We're The following function implements these ideas: ```swift -public func randomizedSelect(array: [T], order k: Int) -> T { +public func randomizedSelect(_ array: [T], order k: Int) -> T { var a = array - func randomPivot(inout a: [T], _ low: Int, _ high: Int) -> T { + func randomPivot(_ a: inout [T], _ low: Int, _ high: Int) -> T { let pivotIndex = random(min: low, max: high) - swap(&a, pivotIndex, high) + a.swapAt(pivotIndex, high) return a[high] } - func randomizedPartition(inout a: [T], _ low: Int, _ high: Int) -> Int { + func randomizedPartition(_ a: inout [T], _ low: Int, _ high: Int) -> Int { let pivot = randomPivot(&a, low, high) var i = low for j in low..(inout a: [T], _ low: Int, _ high: Int, _ k: Int) -> T { + func randomizedSelect(_ a: inout [T], _ low: Int, _ high: Int, _ k: Int) -> T { if low < high { let p = randomizedPartition(&a, low, high) if k == p { From 2924b2dced521f2ccf3a0f276f3f58f57822f914 Mon Sep 17 00:00:00 2001 From: i303071 Date: Mon, 29 Jan 2018 11:04:29 +0100 Subject: [PATCH 056/327] HashTable CustomStringConvertible conformance in protocol --- .../Sources/HashTable.swift | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/Hash Table/HashTable.playground/Sources/HashTable.swift b/Hash Table/HashTable.playground/Sources/HashTable.swift index 2383b8192..476a51174 100644 --- a/Hash Table/HashTable.playground/Sources/HashTable.swift +++ b/Hash Table/HashTable.playground/Sources/HashTable.swift @@ -30,7 +30,7 @@ Insert: O(1) O(n) Delete: O(1) O(n) */ -public struct HashTable: CustomStringConvertible { +public struct HashTable { private typealias Element = (key: Key, value: Value) private typealias Bucket = [Element] private var buckets: [Bucket] @@ -41,23 +41,6 @@ public struct HashTable: CustomStringConvertible { /// A Boolean value that indicates whether the hash table is empty. public var isEmpty: Bool { return count == 0 } - /// A string that represents the contents of the hash table. - public var description: String { - let pairs = buckets.flatMap { b in b.map { e in "\(e.key) = \(e.value)" } } - return pairs.joined(separator: ", ") - } - - /// A string that represents the contents of - /// the hash table, suitable for debugging. - public var debugDescription: String { - var str = "" - for (i, bucket) in buckets.enumerated() { - let pairs = bucket.map { e in "\(e.key) = \(e.value)" } - str += "bucket \(i): " + pairs.joined(separator: ", ") + "\n" - } - return str - } - /** Create a hash table with the given capacity. */ @@ -151,3 +134,22 @@ public struct HashTable: CustomStringConvertible { return abs(key.hashValue) % buckets.count } } + +extension HashTable: CustomStringConvertible { + /// A string that represents the contents of the hash table. + public var description: String { + let pairs = buckets.flatMap { b in b.map { e in "\(e.key) = \(e.value)" } } + return pairs.joined(separator: ", ") + } + + /// A string that represents the contents of + /// the hash table, suitable for debugging. + public var debugDescription: String { + var str = "" + for (i, bucket) in buckets.enumerated() { + let pairs = bucket.map { e in "\(e.key) = \(e.value)" } + str += "bucket \(i): " + pairs.joined(separator: ", ") + "\n" + } + return str + } +} From 5beb84acec563fefef04ce87683484e4359f5350 Mon Sep 17 00:00:00 2001 From: Keith Date: Wed, 31 Jan 2018 23:40:15 +0800 Subject: [PATCH 057/327] Update README.markdown when k > n/2 , we just need random select a.count - k elements and remove them from the original array --- Selection Sampling/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Selection Sampling/README.markdown b/Selection Sampling/README.markdown index ff80791e1..741f592f4 100644 --- a/Selection Sampling/README.markdown +++ b/Selection Sampling/README.markdown @@ -193,7 +193,7 @@ print(output.count) The performance of this second algorithm is **O(n)** as it may require a pass through the entire input array. -> **Note:** If `k > n/2`, then it's more efficient to do it the other way around and choose `k` items to remove. +> **Note:** If `k > n/2`, then it's more efficient to do it the other way around and choose `a.count - k` items to remove. Based on code from Algorithm Alley, Dr. Dobb's Magazine, October 1993. From f34ccf2f6fb873bbf1b21fa39841534dbb5a04c4 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Wed, 7 Feb 2018 02:11:29 -0800 Subject: [PATCH 058/327] English Edit --- Introsort/README.markdown | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Introsort/README.markdown b/Introsort/README.markdown index c4ee6f804..376703cf7 100644 --- a/Introsort/README.markdown +++ b/Introsort/README.markdown @@ -6,7 +6,7 @@ IntroSort is the algorithm used by swift to sort a collection. Introsort is an h The number 20 is an empiric number obtained observing the behaviour of InsertionSort with lists of this size. -Here's an implementation in Pseudocode: +Here's an implementation in pseudocode: ``` procedure sort(A : array): @@ -32,9 +32,9 @@ Let's walk through the example. The array is initially: [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ] -for this example let's assume that `maxDepth` is **2** and that the size of the partition for the insertionSort to kick in is **5** +For this example let's assume that `maxDepth` is **2** and that the size of the partition for the insertionSort to kick in is **5** -At the first iteration we run introSort on the full collection that counts 13 elements. the maxDepth is 2, therefore we fall in the else case where quicksort acts. +The first iteration of introsort begins by attempting to use insertionSort. The collection has 13 elements, so it tries to do heapsort instead. The condition for heapsort to occur is if `maxdepth == 0` evaluates true. Since `maxdepth` is currently **2** for the first iteration, introsort will default to quicksort. The `partition` method picks the first element, the median and the last, it sorts them and uses the new median as pivot. @@ -106,5 +106,6 @@ The array is now successfully sorted [Introsort on Wikipedia](https://en.wikipedia.org/wiki/Introsort) [Introsort comparison with other sorting algorithms](http://agostini.tech/2017/12/18/swift-sorting-algorithm/) +[Introsort implementation from the Swift standard library](https://github.com/apple/swift/blob/09f77ff58d250f5d62855ea359fc304f40b531df/stdlib/public/core/Sort.swift.gyb) *Written for Swift Algorithm Club by Giuseppe Lanza* From b59cd5f6b28130146cd03384e926ac5c4ff2622d Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Fri, 23 Feb 2018 15:30:42 -0600 Subject: [PATCH 059/327] working on readme.. finally finishing this PR --- Genetic/README.markdown | 169 ++++++++++++++++++- Genetic/gen.playground/Contents.swift | 91 ++++++++++ Genetic/gen.playground/contents.xcplayground | 4 + Genetic/gen.swift | 38 +++-- 4 files changed, 282 insertions(+), 20 deletions(-) create mode 100644 Genetic/gen.playground/Contents.swift create mode 100644 Genetic/gen.playground/contents.xcplayground diff --git a/Genetic/README.markdown b/Genetic/README.markdown index 7cad649cb..fd208a19d 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -1,2 +1,167 @@ -# todo -refactoring https://gist.github.com/blainerothrock/efda6e12fe10792c99c990f8ff3daeba for swift 4. Creating a tutorial and writing in more playground friendly format +# Genetic Algorthim + +## What is it? + +A genetic algorithm (GA) is process inspired by natural selection to find high quality solutions. Most commonly used for optimization. GAs rely on the bio-inspired processes of natural selection, more specifically the process of selection (fitness), mutation and crossover. To understand more, let's walk through these process in terms of biology: + +### Selection +>**Selection**, in biology, the preferential survival and reproduction or preferential elimination of individuals with certain genotypes (genetic compositions), by means of natural or artificial controlling factors. [Britannica](britannica) + +In other words, survival of the fittest. Organism that survive in their environment tend to reproduce more. With GAs we generate a fitness model that will rank offspring and give them a better chance for reproduction. + +### Mutation +>**Mutation**, an alteration in the genetic material (the genome) of a cell of a living organism or of a virus that is more or less permanent and that can be transmitted to the cell’s or the virus’s descendants. [Britannica](https://www.britannica.com/science/mutation-genetics) + +The randomization that allows for organisms to change over time. In GAs we build a randomization process that will mutate offspring in a populate in order to randomly introduce fitness variance. + +### Crossover +>**Chromosomal crossover** (or crossing over) is the exchange of genetic material between homologous chromosomes that results in recombinant chromosomes during sexual reproduction [Wikipedia](https://en.wikipedia.org/wiki/Chromosomal_crossover) + +Simply reproduction. A generation will a mixed representation of the previous generation, with offspring taking data (DNA) from both parents. GAs do this by randomly, but weightily, mating offspring to create new generations. + +### Resources: +* [Wikipedia]() + + +## The Code + +### Problem +For this quick and dirty example, we are going to obtain a optimize string using a simple genetic algorithm. More specifically we are trying to take a randomly generated origin string of a fixed length and evolve it into the most optimized string of our choosing. + +We will be creating a bio-inspired world where the absolute existence is string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible. + +### Define the Universe + +Before we dive into the core processes we need to set up our "universe". First let's define a lexicon, a set of everything that exists in our universe. + +```swift +let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray +``` + +To make things easier, we are actually going to work in ASCII values, so let's define a String extension to help with that. + +```swift +extension String { + var asciiArray: [UInt8] { + return [UInt8](self.utf8) + } +} +``` + + Now, let's define a few global variables for the universe: + + ```swift +// This is the end goal and what we will be using to rate fitness. In the real world this will not exist +let OPTIMAL:[UInt8] = "Hello, World".asciiArray + +// The length of the string in our population. Organisms need to be similar +let DNA_SIZE = OPTIMAL.count + +// size of each generation +let POP_SIZE = 50 + +// max number of generations, script will stop when it reach 5000 if the optimal value is not found +let GENERATIONS = 5000 + +// The chance in which a random nucleotide can mutate (1/n) +let MUTATION_CHANCE = 100 + ``` + + The last piece we need for set up is a function to give us a random ASCII value from our lexicon: + + ```swift + func randomChar(from lexicon: [UInt8]) -> UInt8 { + let len = UInt32(lexicon.count-1) + let rand = Int(arc4random_uniform(len)) + return lexicon[rand] + } + ``` + + ### Population Zero + + Before selecting, mutating and reproduction, we need population to start with. Now that we have the universe defined we can write that function: + + ```swift + func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { + + let len = UInt32(lexicon.count) + + var pop = [[UInt8]]() + + for _ in 0.. Int { + var fitness = 0 + for c in 0...dna.count-1 { + fitness += abs(Int(dna[c]) - Int(optimal[c])) + } + return fitness +} +``` + +The above is a very simple fitness calculation, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. + +The second part to selection is weighted choice, also called roulette wheel selection. This defines how individuals are selected for the reproduction process out of the current population. Just because you are the best choice for natural selection doesn't mean the environment will select you. The individual could fall off a cliff, get dysentery or not be able to reproduce. + +Let's take a second and ask why on this one. Why would you not always want to select the most fit from a population? It's hard to see from this simple example, but let's think about dog breeding, because breeders remove this process and hand select dogs for the next generation. As a result you get improved desired characteristics, but the individuals will also continue to carry genetic disorders that come along with those traits. This is essentially leading the evolution down a linear path. A certain "branch" of evolution may beat out the current fittest solution at a later time. + +ok, back to code. Here is our weighted choice function: + +```swift +func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { + + let total = items.reduce(0.0) { return $0 + $1.weight} + + var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 + + for itemTuple in items { + if n < itemTuple.weight { + return itemTuple + } + n = n - itemTuple.weight + } + return items[1] +} +``` + +The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. + +## Mutation + +The all powerful mutation. The great randomization that turns bacteria into humans, just add time. So powerful yet so simple: + +```swift +func mutate(dna:[UInt8], mutationChance:Int) -> [UInt8] { + var outputDna = dna + + for i in 0..?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray + +// This is the end goal and what we will be using to rate fitness. In the real world this will not exist +let OPTIMAL:[UInt8] = "Hello, World".asciiArray + +// The length of the string in our population. Organisms need to be similar +let DNA_SIZE = OPTIMAL.count + +// size of each generation +let POP_SIZE = 50 + +// max number of generations, script will stop when it reach 5000 if the optimal value is not found +let GENERATIONS = 5000 + +// The chance in which a random nucleotide can mutate (1/n) +let MUTATION_CHANCE = 100 + +func randomChar(from lexicon: [UInt8]) -> UInt8 { + let len = UInt32(lexicon.count-1) + let rand = Int(arc4random_uniform(len)) + return lexicon[rand] +} + +func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { + + let len = UInt32(lexicon.count) + + var pop = [[UInt8]]() + + for _ in 0.. Int { + + var fitness = 0 + for c in 0...dna.count-1 { + fitness += abs(Int(dna[c]) - Int(optimal[c])) + } + return fitness +} + +calculateFitness(dna: "Hillo, World".asciiArray, optimal: "Hello, World".asciiArray) + +func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { + + let total = items.reduce(0.0) { return $0 + $1.weight} + + var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 + + for itemTuple in items { + if n < itemTuple.weight { + return itemTuple + } + n = n - itemTuple.weight + } + return items[1] +} + +func mutate(dna:[UInt8], mutationChance:Int) -> [UInt8] { + var outputDna = dna + + for i in 0.. + + + \ No newline at end of file diff --git a/Genetic/gen.swift b/Genetic/gen.swift index 72830b8a7..17df6d002 100644 --- a/Genetic/gen.swift +++ b/Genetic/gen.swift @@ -14,14 +14,16 @@ extension String { } } +let lex = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".map { } + /* helper function to return a random character string */ func randomChar() -> UInt8 { - + let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray let len = UInt32(letters.count-1) - + let rand = Int(arc4random_uniform(len)) return letters[rand] } @@ -40,7 +42,7 @@ let MUTATION_CHANCE = 100 optimal string comparsion = 0 */ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { - + var fitness = 0 for c in 0...dna.count-1 { fitness += abs(Int(dna[c]) - Int(optimal[c])) @@ -53,7 +55,7 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { */ func mutate(dna:[UInt8], mutationChance:Int, dnaSize:Int) -> [UInt8] { var outputDna = dna - + for i in 0.. [UInt8] { */ func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[UInt8]) { let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) - + let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) - + return ( [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) @@ -85,12 +87,12 @@ func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[ returns a random population, used to start the evolution */ func randomPopulation(populationSize: Int, dnaSize: Int) -> [[UInt8]] { - + let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray let len = UInt32(letters.count) var pop = [[UInt8]]() - + for _ in 0.. (item:[UInt8], wei for itemTuple in items { weightTotal += itemTuple.weight; } - + var n = Double(arc4random_uniform(UInt32(weightTotal * 1000000.0))) / 1000000.0 for itemTuple in items { @@ -133,36 +135,36 @@ func main() { for generation in 0...GENERATIONS { print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") - + var weightedPopulation = [(item:[UInt8], weight:Double)]() - + // calulcated the fitness of each individual in the population // and add it to the weight population (weighted = 1.0/fitness) for individual in population { let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) - + let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) - + weightedPopulation.append(pair) } - + population = [] - + // create a new generation using the individuals in the origional population for _ in 0...POP_SIZE/2 { let ind1 = weightedChoice(items: weightedPopulation) let ind2 = weightedChoice(items: weightedPopulation) - + let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) // append to the population and mutate population.append(mutate(dna: offspring.dna1, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) population.append(mutate(dna: offspring.dna2, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) } - + fittest = population[0] var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) - + // parse the population for the fittest string for indv in population { let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) From c6381646601bb162f650106c2e8ddcd4c9cb86f6 Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Fri, 23 Feb 2018 16:05:01 -0600 Subject: [PATCH 060/327] readme updates --- Genetic/README.markdown | 30 +++++++++++++++++-- Genetic/gen.playground/Contents.swift | 19 ++++++++++-- .../contents.xcworkspacedata | 7 +++++ 3 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Genetic/README.markdown b/Genetic/README.markdown index fd208a19d..6ebbf2cf7 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -114,7 +114,9 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { } ``` -The above is a very simple fitness calculation, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. +The above will produce a fitness value to an individual. The perfect solution, "Hello, World" will have a fitness of 0. "Gello, World" will have a fitness of 1 since it is one ASCII value off from the optimal. + +This example is very, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. The second part to selection is weighted choice, also called roulette wheel selection. This defines how individuals are selected for the reproduction process out of the current population. Just because you are the best choice for natural selection doesn't mean the environment will select you. The individual could fall off a cliff, get dysentery or not be able to reproduce. @@ -146,13 +148,13 @@ The above function takes a list of individuals with their calculated fitness. Th The all powerful mutation. The great randomization that turns bacteria into humans, just add time. So powerful yet so simple: ```swift -func mutate(dna:[UInt8], mutationChance:Int) -> [UInt8] { +func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna for i in 0.. (dna1:[UInt8], dna2:[UInt8]) { + let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) + + let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) + let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) + + return ( + [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), + [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) + ) +} +``` + +The above is used to generate a completely new generation based on the current generation. + +## Putting it all together -- Running the Genetic Algorithm + +We now have all the methods we need to kick off the process. What is missing a `main()` function that loops though each generation of the GA. diff --git a/Genetic/gen.playground/Contents.swift b/Genetic/gen.playground/Contents.swift index b84fd13e3..50d4c4fc8 100644 --- a/Genetic/gen.playground/Contents.swift +++ b/Genetic/gen.playground/Contents.swift @@ -60,7 +60,7 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { return fitness } -calculateFitness(dna: "Hillo, World".asciiArray, optimal: "Hello, World".asciiArray) +calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray) func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { @@ -77,15 +77,28 @@ func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], wei return items[1] } -func mutate(dna:[UInt8], mutationChance:Int) -> [UInt8] { +func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna for i in 0.. (dna1:[UInt8], dna2:[UInt8]) { + let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) + + let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) + let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) + + return ( + [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), + [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) + ) +} diff --git a/Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata b/Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + From 247c308a0ae5c4c18a89f5b58be5e770a673be22 Mon Sep 17 00:00:00 2001 From: horita-yuya Date: Tue, 27 Feb 2018 20:51:41 +0900 Subject: [PATCH 061/327] :tada: Add Myers Difference Algorithm directory and playground --- .../MyersDifferenceAlgorithm.playground/Contents.swift | 5 +++++ .../contents.xcplayground | 4 ++++ .../timeline.xctimeline | 6 ++++++ swift-algorithm-club.xcworkspace/contents.xcworkspacedata | 7 +++++++ 4 files changed, 22 insertions(+) create mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift create mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground create mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift new file mode 100644 index 000000000..c9a67424b --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift @@ -0,0 +1,5 @@ +//: Playground - noun: a place where people can play + +import UIKit + +var str = "Hello, playground" diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline new file mode 100644 index 000000000..bf468afec --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 142713e62..5d5bf1906 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -51,6 +51,13 @@ + + + + From 574a19e22890585752b505f9905e2c2dbcd185b4 Mon Sep 17 00:00:00 2001 From: horita-yuya Date: Tue, 27 Feb 2018 21:54:29 +0900 Subject: [PATCH 062/327] :sparkles: Add Myers Algorithm source code --- .../Contents.swift | 21 +++++- .../Sources/MyersDifferenceAlgorithm.swift | 67 +++++++++++++++++++ .../timeline.xctimeline | 6 -- .../MyersDifferenceAlgorithm.swift | 67 +++++++++++++++++++ Myers Difference Algorithm/README.md | 2 + .../contents.xcworkspacedata | 6 ++ 6 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift delete mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline create mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.swift create mode 100644 Myers Difference Algorithm/README.md diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift index c9a67424b..113487acc 100644 --- a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift @@ -1,5 +1,22 @@ //: Playground - noun: a place where people can play +import Foundation -import UIKit +let shortestEditDistance: ([String], [String]) -> Int = MyersDifferenceAlgorithm.calculateShortestEditDistance(from:to:) -var str = "Hello, playground" +/*** + All elements are same, so any scripts do not need. + So, the edit distance is 0 + ***/ +shortestEditDistance(["1", "2", "3"], ["1", "2", "3"]) + +/*** + Last element "3" should be inserted. + So, the edit distance is 1 + ***/ +shortestEditDistance(["1", "2"], ["1", "2", "3"]) + +/*** + First, remove "1", then insert "1" after "2". + So, the edit distance is 2 +***/ +shortestEditDistance(["1", "2", "3"], ["2", "1", "3"]) diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift new file mode 100644 index 000000000..aedbf3e71 --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift @@ -0,0 +1,67 @@ +// +// MyersDifferenceAlgorithm.swift +// +// Created by Yuya Horita on 2018/02/27. +// Copyright © 2018年 hy. All rights reserved. +// + +import Foundation + +public struct MyersDifferenceAlgorithm { + public static func calculateShortestEditDistance(from fromArray: Array, to toArray: Array) -> Int { + let fromCount = fromArray.count + let toCount = toArray.count + let totalCount = toCount + fromCount + var furthestReaching = Array(repeating: 0, count: 2 * totalCount + 1) + + let isReachedAtSink: (Int, Int) -> Bool = { x, y in + return x == fromCount && y == toCount + } + + let snake: (Int, Int, Int) -> Int = { x, D, k in + var _x = x + while _x < fromCount && _x - k < toCount && fromArray[_x] == toArray[_x - k] { + _x += 1 + } + return _x + } + + for D in 0...totalCount { + for k in stride(from: -D, through: D, by: 2) { + let index = k + totalCount + + // (x, D, k) => the x position on the k_line where the number of scripts is D + // scripts means insertion or deletion + var x = 0 + if D == 0 { } + // k == -D, D will be the boundary k_line + // when k == -D, moving right on the Edit Graph(is delete script) from k - 1_line where D - 1 is unavailable. + // when k == D, moving bottom on the Edit Graph(is insert script) from k + 1_line where D - 1 is unavailable. + // furthestReaching x position has higher calculating priority. (x, D - 1, k - 1), (x, D - 1, k + 1) + else if k == -D || k != D && furthestReaching[index - 1] < furthestReaching[index + 1] { + // Getting initial x position + // ,using the furthestReaching X position on the k + 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k + 1) + moving bottom + snake + // this moving bottom on the edit graph is compatible with insert script + x = furthestReaching[index + 1] + } else { + // Getting initial x position + // ,using the futrhest X position on the k - 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k - 1) + moving right + snake + // this moving right on the edit graph is compatible with delete script + x = furthestReaching[index - 1] + 1 + } + + // snake + // diagonal moving can be performed with 0 cost. + // `same` script is needed ? + let _x = snake(x, D, k) + + if isReachedAtSink(_x, _x - k) { return D } + furthestReaching[index] = _x + } + } + + fatalError("Never comes here") + } +} diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.swift new file mode 100644 index 000000000..aedbf3e71 --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.swift @@ -0,0 +1,67 @@ +// +// MyersDifferenceAlgorithm.swift +// +// Created by Yuya Horita on 2018/02/27. +// Copyright © 2018年 hy. All rights reserved. +// + +import Foundation + +public struct MyersDifferenceAlgorithm { + public static func calculateShortestEditDistance(from fromArray: Array, to toArray: Array) -> Int { + let fromCount = fromArray.count + let toCount = toArray.count + let totalCount = toCount + fromCount + var furthestReaching = Array(repeating: 0, count: 2 * totalCount + 1) + + let isReachedAtSink: (Int, Int) -> Bool = { x, y in + return x == fromCount && y == toCount + } + + let snake: (Int, Int, Int) -> Int = { x, D, k in + var _x = x + while _x < fromCount && _x - k < toCount && fromArray[_x] == toArray[_x - k] { + _x += 1 + } + return _x + } + + for D in 0...totalCount { + for k in stride(from: -D, through: D, by: 2) { + let index = k + totalCount + + // (x, D, k) => the x position on the k_line where the number of scripts is D + // scripts means insertion or deletion + var x = 0 + if D == 0 { } + // k == -D, D will be the boundary k_line + // when k == -D, moving right on the Edit Graph(is delete script) from k - 1_line where D - 1 is unavailable. + // when k == D, moving bottom on the Edit Graph(is insert script) from k + 1_line where D - 1 is unavailable. + // furthestReaching x position has higher calculating priority. (x, D - 1, k - 1), (x, D - 1, k + 1) + else if k == -D || k != D && furthestReaching[index - 1] < furthestReaching[index + 1] { + // Getting initial x position + // ,using the furthestReaching X position on the k + 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k + 1) + moving bottom + snake + // this moving bottom on the edit graph is compatible with insert script + x = furthestReaching[index + 1] + } else { + // Getting initial x position + // ,using the futrhest X position on the k - 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k - 1) + moving right + snake + // this moving right on the edit graph is compatible with delete script + x = furthestReaching[index - 1] + 1 + } + + // snake + // diagonal moving can be performed with 0 cost. + // `same` script is needed ? + let _x = snake(x, D, k) + + if isReachedAtSink(_x, _x - k) { return D } + furthestReaching[index] = _x + } + } + + fatalError("Never comes here") + } +} diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md new file mode 100644 index 000000000..def447593 --- /dev/null +++ b/Myers Difference Algorithm/README.md @@ -0,0 +1,2 @@ +# Myers Difference Algorithm + diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 5d5bf1906..5b8dd996f 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -54,9 +54,15 @@ + + + + Date: Tue, 27 Feb 2018 22:11:02 +0900 Subject: [PATCH 063/327] :sparkles: EditGraph Images were added --- .../Images/EditGraph.png | Bin 0 -> 193070 bytes .../Images/EditGraph_k_move.png | Bin 0 -> 206377 bytes .../contents.xcworkspacedata | 7 +++++++ 3 files changed, 7 insertions(+) create mode 100644 Myers Difference Algorithm/Images/EditGraph.png create mode 100644 Myers Difference Algorithm/Images/EditGraph_k_move.png diff --git a/Myers Difference Algorithm/Images/EditGraph.png b/Myers Difference Algorithm/Images/EditGraph.png new file mode 100644 index 0000000000000000000000000000000000000000..f31bb50a3e8614ed7a6da5eb363f21691ba469e4 GIT binary patch literal 193070 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

    *_zw=cDG{_XK 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


    M_(ro-e<%YlgAiM9m`x9$t3#P`Hs^ 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 MSyh=lX_Kq}2VBnDs{jB1 literal 0 HcmV?d00001 diff --git a/Myers Difference Algorithm/Images/EditGraph_k_move.png b/Myers Difference Algorithm/Images/EditGraph_k_move.png new file mode 100644 index 0000000000000000000000000000000000000000..a8ea45c291a02ce0686f7b247fffe3162914fdf1 GIT binary patch literal 206377 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≫obAIq&=+?zT1Vz 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

    n=>krMYh+QY|x;U8R# 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 literal 0 HcmV?d00001 diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 5b8dd996f..ea6bdfa32 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -54,6 +54,13 @@ + + + + From be679572a9403d8c4c6fb8219b9f08dbda4f0f8c Mon Sep 17 00:00:00 2001 From: horita-yuya Date: Wed, 28 Feb 2018 01:14:33 +0900 Subject: [PATCH 064/327] :pencil: README --- Myers Difference Algorithm/README.md | 145 ++++++++++++++++++ .../contents.xcworkspacedata | 3 + 2 files changed, 148 insertions(+) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index def447593..4e48a704f 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -1,2 +1,147 @@ # Myers Difference Algorithm +Myers Difference Algorithm is the algorithm to find a longest common subsequence or shortest edit scripts (LCS/SES dual probrem) of two sequences by a simple O(ND) time, where N is the sum of the lengths of the two sequences. Common subsequence is the sequence of elements that appear in the same order in both sequences. Edit script will be discussed below. + +For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2", "3", "4"]`, `["2"], ["2", "3"]` are common sequences. Furthermore, the latter `["2", "3"]` is the longest common subsequence. But `["1", "2"], ["3", "2"]` are not. Because, `["1", "2"]` contains `"1"` that is not included in `B`, `["3", 2]` has elements are included in both, but the appearing order is not correct. + +## Finding the length of the Longest Common Subsequence with Myers Algorithm on Edit Graph + +### Edit Graph + +Myers Algorithm uses Edit Graph for solving LCS/SES problem. Edit Graph is the graph like below. + + + +Here, we think about the length of the LCS of sequences `X = [A, B, C, A, B, B, A]`, `Y = [C, B, A, B, A, C]`. + +In Myers Algorithm, edit graph are prepared by + +1. Line the element of sequence `X` on the x axis. And do for `Y` on the y axis. +2. Make grid and vertex at each point in the grid (x, y), `x in [0, N] and y in [0, M]`. `N` is the length of sequence `X`, `M` is of `Y` +3. Line for `x - y = k`, this line called k-line. Pink line is this. +3. Check the points `(i, j)`, where `X[i] = Y[j]`, called match point. +4. Connect vertex `(i - 1, j - 1)` and vertex `(i, j)`, then diagonal edge appears. + +> **Note:** Here, the sequences' start index is 1 not 0, so `X[1] = A`, `Y[1] = C` + +We discuss about which path is the shortest from `source` to `sink`. Can move on the edges on the graph. I mean we can move on the grid, horizontal and vertical edges, and the diagonal edges. + +The movements are compatible with the `Edit Scripts`, insert or delete. The word `Edit Scripts` appeared here, as referred at Introduction SES is Shortest Edit Scripts. + +Let's get back on track. On this edit graph, the horizontal movement to vertex `(i, j)` is compatible with the script `delete at index i from X`, the vertical movement to vertex `(i, j)` is compatible with the script `insert the element of Y at index j to immediately after the element of X at index i`. How about for the diagonal movement?. This movement to vertex `(i, j)` means `X[i] = Y[j]`, so no script needs. + +- horizontal movement -> delete +- vertical movement -> insert +- diagonal movement -> no script because both are same. + +Next, add cost 1 for non-diagonal movement, because they can be compatible with script. And 0 for diagonal movement, same means no script. + +The total cost for the minimum path, exploring from `source` to `sink`, is the same as the length of the Longest Common Subsequence or Shortest Edit Script. + +So, LSC/SES problem can be solved by finding the shortest path from `source` to `sink`. + +### Myers Algorithm + +As mentioned above, the problem of finding a shortest edit script can be reduced to finding a path from `source (0, 0)` to `sink (N, M)` with the fewest number of horizontal and vertical edges. Let `D-path` be a path starting at `source` that has exactly `D` non-diagonal edges, or must move non-diagonally D-times. + +For example, A 0-path consists solely of diagonal edges. This means both sequences are completely same. + +By a simple induction, D-path must consist of a (D-1)-path followed by a non-diagonal edge and then diagonal edges, which called `snake`. The minimum value of D is 0, both sequences being same. To the contrary, the maximum value of D is N + M because delete all elements from X and insert all elements from Y to X is the worst case edit scripts. For getting D, or the length of SES, running loop from 0 to N + M is enough. + +```swift +for D in 0...N + M +``` + +Next, thinking about, where is the furthest reaching point for D-path on k-line. Like below, moving horizontally from k-line reaches (k+1)-line, moving vertically from k-line reaches (k-1)-line. + + + +So, threre are several end points of D-path, or D-path can end on several k-line. We need the information to get the next path ((D+1)-path) as mentioned above. In fact, D-path must end on +k-line, where k in { -D, -D + 2, ....., D - 2, D }. This is so simple, starting point, `source` is `(0, 0)` on (k=0)-line. D is the number of non-diagonal edges and non-diagonal movement changes current k-line to (kpm1)-line. Because 0 is even number, if D is even number D-path will end on (even_k)-line, if D is odd number D-path will end on (odd_k)-line. + +Searching loop outline will be below. + +```swift +for D in 0...N + M { + for k in stride(from: -D, through: D, by: 2) { + //Find the end point of the furthest reaching D-path in k-line. + if furthestReachingX == N && furthestReachingY == M { + // The D-path is the shortest path + // D is the length of Shortest Edit Script + return + } + } +} +``` + +The D-path on k-line can be decomposed into +- a furthest reaching (D-1)-path on (k-1)-line, followed by a horizontal edge, followed by `snake`. +- a furthest reaching (D-1)-path on (k+1)-line, followed by a vertical edge, followed by `snake`. +as discussed above. + +The Myers Algorithm key point are these. +- D-path must end on k-line, where k in { -D, -D + 2, ....., D - 2, D } +- The D-path on k-line can be decomposed into two patterns + +thanks for these, the number of calculation become less. + +```swift +public struct MyersDifferenceAlgorithm { + public static func calculateShortestEditDistance(from fromArray: Array, to toArray: Array) -> Int { + let fromCount = fromArray.count + let toCount = toArray.count + let totalCount = toCount + fromCount + var furthestReaching = Array(repeating: 0, count: 2 * totalCount + 1) + + let isReachedAtSink: (Int, Int) -> Bool = { x, y in + return x == fromCount && y == toCount + } + + let snake: (Int, Int, Int) -> Int = { x, D, k in + var _x = x + while _x < fromCount && _x - k < toCount && fromArray[_x] == toArray[_x - k] { + _x += 1 + } + return _x + } + + for D in 0...totalCount { + for k in stride(from: -D, through: D, by: 2) { + let index = k + totalCount + + // (x, D, k) => the x position on the k_line where the number of scripts is D + // scripts means insertion or deletion + var x = 0 + if D == 0 { } + // k == -D, D will be the boundary k_line + // when k == -D, moving right on the Edit Graph(is delete script) from k - 1_line where D - 1 is unavailable. + // when k == D, moving bottom on the Edit Graph(is insert script) from k + 1_line where D - 1 is unavailable. + // furthestReaching x position has higher calculating priority. (x, D - 1, k - 1), (x, D - 1, k + 1) + else if k == -D || k != D && furthestReaching[index - 1] < furthestReaching[index + 1] { + // Getting initial x position + // ,using the furthestReaching X position on the k + 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k + 1) + moving bottom + snake + // this moving bottom on the edit graph is compatible with insert script + x = furthestReaching[index + 1] + } else { + // Getting initial x position + // ,using the futrhest X position on the k - 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k - 1) + moving right + snake + // this moving right on the edit graph is compatible with delete script + x = furthestReaching[index - 1] + 1 + } + + // snake + // diagonal moving can be performed with 0 cost. + // `same` script is needed ? + let _x = snake(x, D, k) + + if isReachedAtSink(_x, _x - k) { return D } + furthestReaching[index] = _x + } + } + + fatalError("Never comes here") + } +} +``` diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index ea6bdfa32..724755669 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -60,6 +60,9 @@ + + From b22d54af4185f54947cf143e2bf03359eb2263b8 Mon Sep 17 00:00:00 2001 From: horita-yuya Date: Wed, 28 Feb 2018 01:36:54 +0900 Subject: [PATCH 065/327] :hammer: fix typo and description --- Myers Difference Algorithm/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index 4e48a704f..2f6c3c579 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -2,7 +2,7 @@ Myers Difference Algorithm is the algorithm to find a longest common subsequence or shortest edit scripts (LCS/SES dual probrem) of two sequences by a simple O(ND) time, where N is the sum of the lengths of the two sequences. Common subsequence is the sequence of elements that appear in the same order in both sequences. Edit script will be discussed below. -For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2", "3", "4"]`, `["2"], ["2", "3"]` are common sequences. Furthermore, the latter `["2", "3"]` is the longest common subsequence. But `["1", "2"], ["3", "2"]` are not. Because, `["1", "2"]` contains `"1"` that is not included in `B`, `["3", 2]` has elements are included in both, but the appearing order is not correct. +For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2", "3", "4"]`, `["2"], ["2", "3"]` are common sequences. Furthermore, the latter `["2", "3"]` is the longest common subsequence. But `["1", "2"], ["3", "2"]` are not. Because, `["1", "2"]` contains `"1"` that is not included in `B`, `["3", "2"]` has elements are included in both, but the appearing order is not correct. ## Finding the length of the Longest Common Subsequence with Myers Algorithm on Edit Graph @@ -10,7 +10,7 @@ For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2" Myers Algorithm uses Edit Graph for solving LCS/SES problem. Edit Graph is the graph like below. - + Here, we think about the length of the LCS of sequences `X = [A, B, C, A, B, B, A]`, `Y = [C, B, A, B, A, C]`. @@ -18,15 +18,15 @@ In Myers Algorithm, edit graph are prepared by 1. Line the element of sequence `X` on the x axis. And do for `Y` on the y axis. 2. Make grid and vertex at each point in the grid (x, y), `x in [0, N] and y in [0, M]`. `N` is the length of sequence `X`, `M` is of `Y` -3. Line for `x - y = k`, this line called k-line. Pink line is this. -3. Check the points `(i, j)`, where `X[i] = Y[j]`, called match point. -4. Connect vertex `(i - 1, j - 1)` and vertex `(i, j)`, then diagonal edge appears. +3. Line for `x - y = k`, this line called k-line. Black dot line is this and pink number is the value of k. +3. Check the points `(i, j)`, where `X[i] = Y[j]`, called match point, light green one. +4. Connect vertex `(i - 1, j - 1)` and vertex `(i, j)`, where `(i, j)` is match point, then diagonal edge appears. > **Note:** Here, the sequences' start index is 1 not 0, so `X[1] = A`, `Y[1] = C` We discuss about which path is the shortest from `source` to `sink`. Can move on the edges on the graph. I mean we can move on the grid, horizontal and vertical edges, and the diagonal edges. -The movements are compatible with the `Edit Scripts`, insert or delete. The word `Edit Scripts` appeared here, as referred at Introduction SES is Shortest Edit Scripts. +The movements are compatible with the `Edit Scripts`, insert or delete. The word `Edit Scripts` appeared here, as referred at Introduction, SES is Shortest Edit Scripts. Let's get back on track. On this edit graph, the horizontal movement to vertex `(i, j)` is compatible with the script `delete at index i from X`, the vertical movement to vertex `(i, j)` is compatible with the script `insert the element of Y at index j to immediately after the element of X at index i`. How about for the diagonal movement?. This movement to vertex `(i, j)` means `X[i] = Y[j]`, so no script needs. @@ -38,7 +38,7 @@ Next, add cost 1 for non-diagonal movement, because they can be compatible with The total cost for the minimum path, exploring from `source` to `sink`, is the same as the length of the Longest Common Subsequence or Shortest Edit Script. -So, LSC/SES problem can be solved by finding the shortest path from `source` to `sink`. +So, LCS/SES problem can be solved by finding the shortest path from `source` to `sink`. ### Myers Algorithm @@ -52,9 +52,9 @@ By a simple induction, D-path must consist of a (D-1)-path followed by a non-dia for D in 0...N + M ``` -Next, thinking about, where is the furthest reaching point for D-path on k-line. Like below, moving horizontally from k-line reaches (k+1)-line, moving vertically from k-line reaches (k-1)-line. +Next, thinking about, where is the furthest reaching point for D-path on k-line. Like below, moving horizontally from k-line reaches (k+1)-line, moving vertically from k-line reaches (k-1)-line. Red chalky line shows that. - + So, threre are several end points of D-path, or D-path can end on several k-line. We need the information to get the next path ((D+1)-path) as mentioned above. In fact, D-path must end on k-line, where k in { -D, -D + 2, ....., D - 2, D }. This is so simple, starting point, `source` is `(0, 0)` on (k=0)-line. D is the number of non-diagonal edges and non-diagonal movement changes current k-line to (kpm1)-line. Because 0 is even number, if D is even number D-path will end on (even_k)-line, if D is odd number D-path will end on (odd_k)-line. From 81befa64507475361183cd52d29b14ce65da2e03 Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Mon, 5 Mar 2018 09:22:32 -0600 Subject: [PATCH 066/327] tutorial; weighted choice --- Genetic/README.markdown | 49 +++++++- Genetic/gen.playground/Contents.swift | 52 +++++++++ Genetic/gen.swift | 154 +++++++++++--------------- 3 files changed, 167 insertions(+), 88 deletions(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index 6ebbf2cf7..fdc6d5d92 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -188,4 +188,51 @@ The above is used to generate a completely new generation based on the current g ## Putting it all together -- Running the Genetic Algorithm -We now have all the methods we need to kick off the process. What is missing a `main()` function that loops though each generation of the GA. +We now have all the functions we need to kick off the algorthim. Let's start from the beginning, first we need a random population to serve as a starting point. We will also initialize a fittest variable to hold the fittest individual, we will initialize it with the first individual of our random population. + +```swift +var population:[[UInt8]] = randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE) +var fittest = population[0] +``` + +Now for the meat, the remainder of the code will take place in the generation loop, running once for every generation: + +```swift +for generation in 0...GENERATIONS { + // run +} +``` + +Now, for each individual in the population, we need to calculate its fitness and weighted value. For weighted choice we store the fitness as a percent `1 / fitness`. + +```swift +var weightedPopulation = [(item:[UInt8], weight:Double)]() + +for individual in population { + let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) + let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) + weightedPopulation.append(pair) +} +``` + +To understand weighted choice, let walk though a smaller example, let's say we have the following population, where 0 is the best fitness: + +```txt +1: 10 +2: 5 +3: 4 +4: 7 +5: 11 +``` + +Now here is the weight of each: + +```txt +1: +2: +3: +4: +5: + +total = +``` diff --git a/Genetic/gen.playground/Contents.swift b/Genetic/gen.playground/Contents.swift index 50d4c4fc8..4c67f8bd1 100644 --- a/Genetic/gen.playground/Contents.swift +++ b/Genetic/gen.playground/Contents.swift @@ -102,3 +102,55 @@ func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[ [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) ) } + +func main() { + + // generate the starting random population + var population:[[UInt8]] = randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE) + // print("population: \(population), dnaSize: \(DNA_SIZE) ") + var fittest = [UInt8]() + + for generation in 0...GENERATIONS { + print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") + + var weightedPopulation = [(item:[UInt8], weight:Double)]() + + // calulcated the fitness of each individual in the population + // and add it to the weight population (weighted = 1.0/fitness) + for individual in population { + let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) + + let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) + + weightedPopulation.append(pair) + } + + population = [] + + // create a new generation using the individuals in the origional population + for _ in 0...POP_SIZE/2 { + let ind1 = weightedChoice(items: weightedPopulation) + let ind2 = weightedChoice(items: weightedPopulation) + + let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) + + // append to the population and mutate + population.append(mutate(lexicon: lex, dna: offspring.dna1, mutationChance: MUTATION_CHANCE)) + population.append(mutate(lexicon: lex, dna: offspring.dna2, mutationChance: MUTATION_CHANCE)) + } + + fittest = population[0] + var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) + + // parse the population for the fittest string + for indv in population {lex + let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) + if indvFitness < minFitness { + fittest = indv + minFitness = indvFitness + } + } + if minFitness == 0 { break; } + } + print("fittest string: \(String(bytes: fittest, encoding: .ascii)!)") +} diff --git a/Genetic/gen.swift b/Genetic/gen.swift index 17df6d002..f664fd5f7 100644 --- a/Genetic/gen.swift +++ b/Genetic/gen.swift @@ -1,46 +1,56 @@ -/* - base .. to be refactored -*/ +//: Playground - noun: a place where people can play import Foundation -// HELPERS -/* - String extension to convert a string to ascii value -*/ extension String { var asciiArray: [UInt8] { - return unicodeScalars.filter{$0.isASCII}.map{UInt8($0.value)} + return [UInt8](self.utf8) } } -let lex = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".map { } -/* - helper function to return a random character string -*/ -func randomChar() -> UInt8 { +let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray - let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray - let len = UInt32(letters.count-1) +// This is the end goal and what we will be using to rate fitness. In the real world this will not exist +let OPTIMAL:[UInt8] = "Hello, World".asciiArray - let rand = Int(arc4random_uniform(len)) - return letters[rand] -} +// The length of the string in our population. Organisms need to be similar +let DNA_SIZE = OPTIMAL.count -// END HELPERS +// size of each generation +let POP_SIZE = 200 -let OPTIMAL:[UInt8] = "Hello, World".asciiArray -let DNA_SIZE = OPTIMAL.count -let POP_SIZE = 50 +// max number of generations, script will stop when it reach 5000 if the optimal value is not found let GENERATIONS = 5000 + +// The chance in which a random nucleotide can mutate (1/n) let MUTATION_CHANCE = 100 -/* - calculated the fitness based on approximate string matching - compares each character ascii value difference and adds that to a total fitness - optimal string comparsion = 0 -*/ +func randomChar(from lexicon: [UInt8]) -> UInt8 { + let len = UInt32(lexicon.count-1) + let rand = Int(arc4random_uniform(len)) + return lexicon[rand] +} + +func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { + + let len = UInt32(lexicon.count) + + var pop = [[UInt8]]() + + for _ in 0.. Int { var fitness = 0 @@ -50,26 +60,37 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { return fitness } -/* - randomly mutate the string -*/ -func mutate(dna:[UInt8], mutationChance:Int, dnaSize:Int) -> [UInt8] { +calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray) + +func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { + + let total = items.reduce(0.0) { return $0 + $1.weight} + + var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 + + for itemTuple in items { + if n < itemTuple.weight { + return itemTuple + } + n = n - itemTuple.weight + } + return items[1] +} + +func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna - for i in 0.. (dna1:[UInt8], dna2:[UInt8]) { let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) @@ -82,59 +103,15 @@ func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[ ) } - -/* -returns a random population, used to start the evolution -*/ -func randomPopulation(populationSize: Int, dnaSize: Int) -> [[UInt8]] { - - let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray - let len = UInt32(letters.count) - - var pop = [[UInt8]]() - - for _ in 0.. (item:[UInt8], weight:Double) { - var weightTotal = 0.0 - for itemTuple in items { - weightTotal += itemTuple.weight; - } - - var n = Double(arc4random_uniform(UInt32(weightTotal * 1000000.0))) / 1000000.0 - - for itemTuple in items { - if n < itemTuple.weight { - return itemTuple - } - n = n - itemTuple.weight - } - return items[1] -} - func main() { // generate the starting random population - var population:[[UInt8]] = randomPopulation(populationSize: POP_SIZE, dnaSize: DNA_SIZE) + var population:[[UInt8]] = randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE) // print("population: \(population), dnaSize: \(DNA_SIZE) ") var fittest = [UInt8]() for generation in 0...GENERATIONS { - print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") + // print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") var weightedPopulation = [(item:[UInt8], weight:Double)]() @@ -143,7 +120,7 @@ func main() { for individual in population { let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) - let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) + let pair = ( individual, fitnessValue == 0 ? 1.0 : Double(100/POP_SIZE)/Double( fitnessValue ) ) weightedPopulation.append(pair) } @@ -158,15 +135,15 @@ func main() { let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) // append to the population and mutate - population.append(mutate(dna: offspring.dna1, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) - population.append(mutate(dna: offspring.dna2, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) + population.append(mutate(lexicon: lex, dna: offspring.dna1, mutationChance: MUTATION_CHANCE)) + population.append(mutate(lexicon: lex, dna: offspring.dna2, mutationChance: MUTATION_CHANCE)) } fittest = population[0] var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) // parse the population for the fittest string - for indv in population { + for indv in population {lex let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) if indvFitness < minFitness { fittest = indv @@ -174,6 +151,9 @@ func main() { } } if minFitness == 0 { break; } + if generation % 1000 == 0 { + print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") + } } print("fittest string: \(String(bytes: fittest, encoding: .ascii)!)") } From 66f75d2c51b97f51259e8e6706433773e4a6e1af Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Fri, 9 Mar 2018 14:50:30 -0600 Subject: [PATCH 067/327] tutotial complete --- Genetic/README.markdown | 143 +++++++++++++++++++++----- Genetic/gen.playground/Contents.swift | 25 ++--- Genetic/gen.swift | 21 ++-- 3 files changed, 139 insertions(+), 50 deletions(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index fdc6d5d92..92f121daa 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -1,4 +1,4 @@ -# Genetic Algorthim +individual# Genetic Algorthim ## What is it? @@ -20,7 +20,9 @@ The randomization that allows for organisms to change over time. In GAs we build Simply reproduction. A generation will a mixed representation of the previous generation, with offspring taking data (DNA) from both parents. GAs do this by randomly, but weightily, mating offspring to create new generations. ### Resources: -* [Wikipedia]() +* [Genetic Algorithms in Search Optimization, and Machine Learning](https://www.amazon.com/Genetic-Algorithms-Optimization-Machine-Learning/dp/0201157675/ref=sr_1_sc_1?ie=UTF8&qid=1520628364&sr=8-1-spell&keywords=Genetic+Algortithms+in+search) +* [Wikipedia](https://en.wikipedia.org/wiki/Genetic_algorithm) +* [My Original Gist](https://gist.github.com/blainerothrock/efda6e12fe10792c99c990f8ff3daeba) ## The Code @@ -141,7 +143,7 @@ func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], wei } ``` -The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. +The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. The horrible 1,000,000 multiplication and division is to insure precision by calculating decimals. `arc4random` only uses integers so this is required to convert to a precise Double, it's not perfect, but enough for our example. ## Mutation @@ -168,19 +170,16 @@ This allows for a population to explore all the possibilities of it's building b ## Crossover -Crossover, the sexy part of a GA, is how offspring are created from 2 selected individuals in the current population. This is done by splitting the parents into 2 parts, then combining 1 part from each parent to create the offspring. To promote diversity, we randomly select a index to split the parents: +Crossover, the sexy part of a GA, is how offspring are created from 2 selected individuals in the current population. This is done by splitting the parents into 2 parts, then combining 1 part from each parent to create the offspring. To promote diversity, we randomly select a index to split the parents. ```swift -func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[UInt8]) { +func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> [UInt8] { let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) - return ( - [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), - [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) - ) + return [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)) } ``` @@ -203,7 +202,7 @@ for generation in 0...GENERATIONS { } ``` -Now, for each individual in the population, we need to calculate its fitness and weighted value. For weighted choice we store the fitness as a percent `1 / fitness`. +Now, for each individual in the population, we need to calculate its fitness and weighted value. Since 0 is the best value we will use `1/fitness` to represent the weighted value. Note this is not a percent, but just how much more likely the value is to be selected over others. If the highest number was the most fit, the weight calculation would be `fitness/totalFitness`, which would be a percent. ```swift var weightedPopulation = [(item:[UInt8], weight:Double)]() @@ -215,24 +214,118 @@ for individual in population { } ``` -To understand weighted choice, let walk though a smaller example, let's say we have the following population, where 0 is the best fitness: +From here we can start to build the next generation. -```txt -1: 10 -2: 5 -3: 4 -4: 7 -5: 11 +```swift +var nextGeneration = [] +``` + +The below loop is where we pull everything together. We loop for `POP_SIZE`, selecting 2 individuals by weighted choice, crossover their values to produce a offspring, then finial subject the new individual to mutation. Once completed we have a completely new generation based on the last generation. + +```swift +0...POP_SIZE).forEach { _ in + let ind1 = weightedChoice(items: weightedPopulation) + let ind2 = weightedChoice(items: weightedPopulation) + + let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) + + // append to the population and mutate + nextGeneration.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE)) +} +``` + +The final piece to the main loop is to select the fittest individual of a population: + +```swift +fittest = population[0] +var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) + +for indv in population {lex + let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) + if indvFitness < minFitness { + fittest = indv + minFitness = indvFitness + } +} +if minFitness == 0 { break; } +print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") ``` -Now here is the weight of each: +Since we know the fittest string, I've added a `break` to kill the program if we find it. At the end of a loop at a print statement for the fittest string: -```txt -1: -2: -3: -4: -5: +```swift +print("fittest string: \(String(bytes: fittest, encoding: .utf8)!)") +``` -total = +Now we can run the program! Playgrounds are a nice place to develop, but are going to run this program **very slow**. I highly suggest running in Terminal: `swift gen.swift`. When running you should see something like this and it should not take too long to get `Hello, World`: + +```text +0: RXclh F HDko +1: DkyssjgElk]; +2: TiM4u) DrKvZ +3: Dkysu) DrKvZ +4: -kysu) DrKvZ +5: Tlwsu) DrKvZ +6: Tlwsu) Drd}k +7: Tlwsu) Drd}k +8: Tlwsu) Drd}k +9: Tlwsu) Drd}k +10: G^csu) |zd}k +11: G^csu) |zdko +12: G^csu) |zdko +13: Dkysu) Drd}k +14: G^wsu) `rd}k +15: Dkysu) `rdko +16: Dkysu) `rdko +17: Glwsu) `rdko +18: TXysu) `rdkc +19: U^wsu) `rdko +20: G^wsu) `rdko +21: Glysu) `rdko +22: G^ysu) `rdko +23: G^ysu) `ryko +24: G^wsu) `rdko +25: G^wsu) `rdko +26: G^wsu) `rdko +... +1408: Hello, Wormd +1409: Hello, Wormd +1410: Hello, Wormd +1411: Hello, Wormd +1412: Hello, Wormd +1413: Hello, Wormd +1414: Hello, Wormd +1415: Hello, Wormd +1416: Hello, Wormd +1417: Hello, Wormd +1418: Hello, Wormd +1419: Hello, Wormd +1420: Hello, Wormd +1421: Hello, Wormd +1422: Hello, Wormd +1423: Hello, Wormd +1424: Hello, Wormd +1425: Hello, Wormd +1426: Hello, Wormd +1427: Hello, Wormd +1428: Hello, Wormd +1429: Hello, Wormd +1430: Hello, Wormd +1431: Hello, Wormd +1432: Hello, Wormd +1433: Hello, Wormd +1434: Hello, Wormd +1435: Hello, Wormd +fittest string: Hello, World ``` + +How long it takes will vary since this is based on randomization, but it should almost always finish in under 5000 generations. Woo! + + +## Now What? + +We did it, we have a running simple genetic algorithm. Take some time a play around with the global variables, `POP_SIZE`, `OPTIMAL`, `MUTATION_CHANCE`, `GENERATIONS`. Just make sure to only add characters that are in the lexicon, but go ahead and update too! + +For an example let's try something much longer: `Ray Wenderlich's Swift Algorithm Club Rocks`. Plug that string into `OPTIMAL` and change `GENERATIONS` to `10000`. You'll be able to see that the we are getting somewhere, but you most likely will not reach the optimal string in 10,000 generations. Since we have a larger string let's raise our mutation chance to `200` (1/2 as likely to mutate). You may not get there, but you should get a lot closer than before. With a longer string, too much mutate can make it hard for fit strings to survive. Now try either upping `POP_SIZE` or increase `GENERATIONS`. Either way you should eventually get the value, but there will be a "sweet spot" for an individual of a certain size. + +Please submit any kind of update to this tutorial or add more examples! diff --git a/Genetic/gen.playground/Contents.swift b/Genetic/gen.playground/Contents.swift index 4c67f8bd1..8e1976ca6 100644 --- a/Genetic/gen.playground/Contents.swift +++ b/Genetic/gen.playground/Contents.swift @@ -63,7 +63,7 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray) func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { - + let total = items.reduce(0.0) { return $0 + $1.weight} var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 @@ -91,16 +91,13 @@ func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { } -func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[UInt8]) { +func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> [UInt8] { let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) - return ( - [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), - [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) - ) + return [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)) } func main() { @@ -111,7 +108,7 @@ func main() { var fittest = [UInt8]() for generation in 0...GENERATIONS { - print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") + // print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") var weightedPopulation = [(item:[UInt8], weight:Double)]() @@ -120,7 +117,7 @@ func main() { for individual in population { let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) - let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) + let pair = ( individual, fitnessValue == 0 ? 1.0 : Double(100/POP_SIZE)/Double( fitnessValue ) ) weightedPopulation.append(pair) } @@ -128,15 +125,14 @@ func main() { population = [] // create a new generation using the individuals in the origional population - for _ in 0...POP_SIZE/2 { + (0...POP_SIZE).forEach { _ in let ind1 = weightedChoice(items: weightedPopulation) let ind2 = weightedChoice(items: weightedPopulation) let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) // append to the population and mutate - population.append(mutate(lexicon: lex, dna: offspring.dna1, mutationChance: MUTATION_CHANCE)) - population.append(mutate(lexicon: lex, dna: offspring.dna2, mutationChance: MUTATION_CHANCE)) + population.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE)) } fittest = population[0] @@ -151,6 +147,11 @@ func main() { } } if minFitness == 0 { break; } + print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") + } - print("fittest string: \(String(bytes: fittest, encoding: .ascii)!)") + print("fittest string: \(String(bytes: fittest, encoding: .utf8)!)") } + +main() + diff --git a/Genetic/gen.swift b/Genetic/gen.swift index f664fd5f7..a2a1b1410 100644 --- a/Genetic/gen.swift +++ b/Genetic/gen.swift @@ -18,7 +18,7 @@ let OPTIMAL:[UInt8] = "Hello, World".asciiArray let DNA_SIZE = OPTIMAL.count // size of each generation -let POP_SIZE = 200 +let POP_SIZE = 50 // max number of generations, script will stop when it reach 5000 if the optimal value is not found let GENERATIONS = 5000 @@ -91,16 +91,13 @@ func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { } -func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[UInt8]) { +func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> [UInt8] { let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) - return ( - [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), - [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) - ) + return [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)) } func main() { @@ -128,15 +125,14 @@ func main() { population = [] // create a new generation using the individuals in the origional population - for _ in 0...POP_SIZE/2 { + (0...POP_SIZE).forEach { _ in let ind1 = weightedChoice(items: weightedPopulation) let ind2 = weightedChoice(items: weightedPopulation) let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) // append to the population and mutate - population.append(mutate(lexicon: lex, dna: offspring.dna1, mutationChance: MUTATION_CHANCE)) - population.append(mutate(lexicon: lex, dna: offspring.dna2, mutationChance: MUTATION_CHANCE)) + population.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE)) } fittest = population[0] @@ -151,11 +147,10 @@ func main() { } } if minFitness == 0 { break; } - if generation % 1000 == 0 { - print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") - } + print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") + } - print("fittest string: \(String(bytes: fittest, encoding: .ascii)!)") + print("fittest string: \(String(bytes: fittest, encoding: .utf8)!)") } main() From ca6f0f0c71773a9117db63546b7c94b0c8de3a0e Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Fri, 9 Mar 2018 15:32:58 -0600 Subject: [PATCH 068/327] readme updates --- Genetic/README.markdown | 79 ++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index 92f121daa..d6a474a10 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -2,35 +2,34 @@ individual# Genetic Algorthim ## What is it? -A genetic algorithm (GA) is process inspired by natural selection to find high quality solutions. Most commonly used for optimization. GAs rely on the bio-inspired processes of natural selection, more specifically the process of selection (fitness), mutation and crossover. To understand more, let's walk through these process in terms of biology: +A genetic algorithm (GA) is process inspired by natural selection to find high quality solutions. Most commonly used for optimization. GAs rely on the bio-inspired processes of natural selection, more specifically the process of selection (fitness), crossover and mutation. To understand more, let's walk through these processes in terms of biology: ### Selection >**Selection**, in biology, the preferential survival and reproduction or preferential elimination of individuals with certain genotypes (genetic compositions), by means of natural or artificial controlling factors. [Britannica](britannica) -In other words, survival of the fittest. Organism that survive in their environment tend to reproduce more. With GAs we generate a fitness model that will rank offspring and give them a better chance for reproduction. - -### Mutation ->**Mutation**, an alteration in the genetic material (the genome) of a cell of a living organism or of a virus that is more or less permanent and that can be transmitted to the cell’s or the virus’s descendants. [Britannica](https://www.britannica.com/science/mutation-genetics) - -The randomization that allows for organisms to change over time. In GAs we build a randomization process that will mutate offspring in a populate in order to randomly introduce fitness variance. +In other words, survival of the fittest. Organisms that survive in their environment tend to reproduce more. With GAs we generate a fitness model that will rank individuals and give them a better chance for reproduction. ### Crossover >**Chromosomal crossover** (or crossing over) is the exchange of genetic material between homologous chromosomes that results in recombinant chromosomes during sexual reproduction [Wikipedia](https://en.wikipedia.org/wiki/Chromosomal_crossover) -Simply reproduction. A generation will a mixed representation of the previous generation, with offspring taking data (DNA) from both parents. GAs do this by randomly, but weightily, mating offspring to create new generations. +Simply reproduction. A generation will be a mixed representation of the previous generation, with offspring taking DNA from both parents. GAs do this by randomly, but weightily, mating offspring to create new generations. + +### Mutation +>**Mutation**, an alteration in the genetic material (the genome) of a cell of a living organism or of a virus that is more or less permanent and that can be transmitted to the cell’s or the virus’s descendants. [Britannica](https://www.britannica.com/science/mutation-genetics) + +The randomization that allows for organisms to change over time. In GAs we build a randomization process that will mutate offspring in a population in order to introduce fitness variance. ### Resources: * [Genetic Algorithms in Search Optimization, and Machine Learning](https://www.amazon.com/Genetic-Algorithms-Optimization-Machine-Learning/dp/0201157675/ref=sr_1_sc_1?ie=UTF8&qid=1520628364&sr=8-1-spell&keywords=Genetic+Algortithms+in+search) * [Wikipedia](https://en.wikipedia.org/wiki/Genetic_algorithm) * [My Original Gist](https://gist.github.com/blainerothrock/efda6e12fe10792c99c990f8ff3daeba) - ## The Code ### Problem -For this quick and dirty example, we are going to obtain a optimize string using a simple genetic algorithm. More specifically we are trying to take a randomly generated origin string of a fixed length and evolve it into the most optimized string of our choosing. +For this quick and dirty example, we are going to produce an optimized string using a simple genetic algorithm. More specifically we are trying to take a randomly generated origin string of a fixed length and evolve it into the most optimized string of our choosing. -We will be creating a bio-inspired world where the absolute existence is string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible. +We will be creating a bio-inspired world where the absolute existence is the string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible to ensure survival. ### Define the Universe @@ -40,36 +39,32 @@ Before we dive into the core processes we need to set up our "universe". First l let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray ``` -To make things easier, we are actually going to work in ASCII values, so let's define a String extension to help with that. +To make things easier, we are actually going to work in [Unicode values](https://en.wikipedia.org/wiki/List_of_Unicode_characters), so let's define a String extension to help with that. ```swift extension String { - var asciiArray: [UInt8] { + var unicodeArray: [UInt8] { return [UInt8](self.utf8) } } ``` Now, let's define a few global variables for the universe: + * `OPTIMAL`: This is the end goal and what we will be using to rate fitness. In the real world this will not exist + * `DNA_SIZE`: The length of the string in our population. Organisms need to be similar + * `POP_SIZE`: Size of each generation + * `MAX_GENERATIONS`: Max number of generations, script will stop when it reach 5000 if the optimal value is not found + * `MUTATION_CHANCE`: The chance in which a random nucleotide can mutate (`1/MUTATION_CHANCE`) ```swift -// This is the end goal and what we will be using to rate fitness. In the real world this will not exist -let OPTIMAL:[UInt8] = "Hello, World".asciiArray - -// The length of the string in our population. Organisms need to be similar +let OPTIMAL:[UInt8] = "Hello, World".unicodeArray let DNA_SIZE = OPTIMAL.count - -// size of each generation let POP_SIZE = 50 - -// max number of generations, script will stop when it reach 5000 if the optimal value is not found -let GENERATIONS = 5000 - -// The chance in which a random nucleotide can mutate (1/n) +let MAX_GENERATIONS = 5000 let MUTATION_CHANCE = 100 ``` - The last piece we need for set up is a function to give us a random ASCII value from our lexicon: + The last piece we need for set up is a function to give us a random unicode value from our lexicon: ```swift func randomChar(from lexicon: [UInt8]) -> UInt8 { @@ -78,10 +73,12 @@ let MUTATION_CHANCE = 100 return lexicon[rand] } ``` + + **Note**: `arc4random_uniform` is strickly used in this example. It would be fun to play around with some of the [randomization in GameKit](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html) ### Population Zero - Before selecting, mutating and reproduction, we need population to start with. Now that we have the universe defined we can write that function: +Before selecting, crossover and mutation, we need a population to start with. Now that we have the universe defined we can write that function: ```swift func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { @@ -90,9 +87,9 @@ let MUTATION_CHANCE = 100 var pop = [[UInt8]]() - for _ in 0.. Int { var fitness = 0 - for c in 0...dna.count-1 { + (0...dna.count-1).forEach { c in fitness += abs(Int(dna[c]) - Int(optimal[c])) } return fitness } ``` -The above will produce a fitness value to an individual. The perfect solution, "Hello, World" will have a fitness of 0. "Gello, World" will have a fitness of 1 since it is one ASCII value off from the optimal. +The above will produce a fitness value to an individual. The perfect solution, "Hello, World" will have a fitness of 0. "Gello, World" will have a fitness of 1 since it is one unicode value off from the optimal (`H->G`). -This example is very, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. +This example is very simple, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using a GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. In our example we will reach our goal, a fitness of 0. -The second part to selection is weighted choice, also called roulette wheel selection. This defines how individuals are selected for the reproduction process out of the current population. Just because you are the best choice for natural selection doesn't mean the environment will select you. The individual could fall off a cliff, get dysentery or not be able to reproduce. +The second part to selection is weighted choice, also called roulette wheel selection. This defines how individuals are selected for the reproduction process out of the current population. Just because you are the best choice for natural selection doesn't mean the environment will select you. The individual could fall off a cliff, get dysentery or be unable to reproduce. -Let's take a second and ask why on this one. Why would you not always want to select the most fit from a population? It's hard to see from this simple example, but let's think about dog breeding, because breeders remove this process and hand select dogs for the next generation. As a result you get improved desired characteristics, but the individuals will also continue to carry genetic disorders that come along with those traits. This is essentially leading the evolution down a linear path. A certain "branch" of evolution may beat out the current fittest solution at a later time. +Let's take a second and ask why on this one. Why would you not always want to select the most fit from a population? It's hard to see from this simple example, but let's think about dog breeding, because breeders remove this process and hand select dogs for the next generation. As a result you get improved desired characteristics, but the individuals will also continue to carry genetic disorders that come along with those traits. A certain "branch" of evolution may beat out the current fittest solution at a later time. This may be ok depending on the problem, but to keep this educational we will go with the bio-inspired way. -ok, back to code. Here is our weighted choice function: +With all that, here is our weight choice function: ```swift func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { @@ -147,13 +144,13 @@ The above function takes a list of individuals with their calculated fitness. Th ## Mutation -The all powerful mutation. The great randomization that turns bacteria into humans, just add time. So powerful yet so simple: +The all powerful mutation, the thing that introduces otherwise non exisitant fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achive the optimal solution. ```swift func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna - for i in 0.. Date: Fri, 9 Mar 2018 15:43:15 -0600 Subject: [PATCH 069/327] typos --- Genetic/README.markdown | 30 +++++++------- Genetic/gen.playground/Contents.swift | 39 +++++++------------ Genetic/gen.swift | 56 ++++++++++++--------------- 3 files changed, 53 insertions(+), 72 deletions(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index d6a474a10..07547c4b4 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -29,7 +29,7 @@ The randomization that allows for organisms to change over time. In GAs we build ### Problem For this quick and dirty example, we are going to produce an optimized string using a simple genetic algorithm. More specifically we are trying to take a randomly generated origin string of a fixed length and evolve it into the most optimized string of our choosing. -We will be creating a bio-inspired world where the absolute existence is the string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible to ensure survival. +We will be creating a bio-inspired world where the absolute existence is the string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible to ensure survival. ### Define the Universe @@ -73,8 +73,8 @@ let MUTATION_CHANCE = 100 return lexicon[rand] } ``` - - **Note**: `arc4random_uniform` is strickly used in this example. It would be fun to play around with some of the [randomization in GameKit](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html) + + **Note**: `arc4random_uniform` is strictly used in this example. It would be fun to play around with some of the [randomization in GameKit](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html) ### Population Zero @@ -83,8 +83,6 @@ Before selecting, crossover and mutation, we need a population to start with. No ```swift func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { - let len = UInt32(lexicon.count) - var pop = [[UInt8]]() (0.. (item:[UInt8], weight:Double) { +func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { let total = items.reduce(0.0) { return $0 + $1.weight} var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 - for itemTuple in items { - if n < itemTuple.weight { - return itemTuple + for item in items { + if n < item.weight { + return item } - n = n - itemTuple.weight + n = n - item.weight } return items[1] } @@ -144,7 +142,7 @@ The above function takes a list of individuals with their calculated fitness. Th ## Mutation -The all powerful mutation, the thing that introduces otherwise non exisitant fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achive the optimal solution. +The all powerful mutation, the thing that introduces otherwise non existent fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achieve the optimal solution. ```swift func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { @@ -184,7 +182,7 @@ The above is used to generate a completely new generation based on the current g ## Putting it all together -- Running the Genetic Algorithm -We now have all the functions we need to kick off the algorthim. Let's start from the beginning, first we need a random population to serve as a starting point. We will also initialize a fittest variable to hold the fittest individual, we will initialize it with the first individual of our random population. +We now have all the functions we need to kick off the algorithm. Let's start from the beginning, first we need a random population to serve as a starting point. We will also initialize a fittest variable to hold the fittest individual, we will initialize it with the first individual of our random population. ```swift var population:[[UInt8]] = randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE) @@ -202,7 +200,7 @@ for generation in 0...GENERATIONS { Now, for each individual in the population, we need to calculate its fitness and weighted value. Since 0 is the best value we will use `1/fitness` to represent the weight. Note this is not a percent, but just how much more likely the value is to be selected over others. If the highest number was the most fit, the weight calculation would be `fitness/totalFitness`, which would be a percent. ```swift -var weightedPopulation = [(item:[UInt8], weight:Double)]() +var weightedPopulation = [(dna:[UInt8], weight:Double)]() for individual in population { let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) @@ -224,7 +222,7 @@ The below loop is where we pull everything together. We loop for `POP_SIZE`, sel let ind1 = weightedChoice(items: weightedPopulation) let ind2 = weightedChoice(items: weightedPopulation) - let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) + let offspring = crossover(dna1: ind1.dna, dna2: ind2.dna, dnaSize: DNA_SIZE) // append to the population and mutate nextGeneration.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE)) @@ -237,7 +235,7 @@ The final piece to the main loop is to select the fittest individual of a popula fittest = population[0] var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) -for indv in population {lex +population.forEach { indv in let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) if indvFitness < minFitness { fittest = indv diff --git a/Genetic/gen.playground/Contents.swift b/Genetic/gen.playground/Contents.swift index 8e1976ca6..79a398ceb 100644 --- a/Genetic/gen.playground/Contents.swift +++ b/Genetic/gen.playground/Contents.swift @@ -3,16 +3,16 @@ import Foundation extension String { - var asciiArray: [UInt8] { + var unicodeArray: [UInt8] { return [UInt8](self.utf8) } } -let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray +let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".unicodeArray // This is the end goal and what we will be using to rate fitness. In the real world this will not exist -let OPTIMAL:[UInt8] = "Hello, World".asciiArray +let OPTIMAL:[UInt8] = "Hello, World".unicodeArray // The length of the string in our population. Organisms need to be similar let DNA_SIZE = OPTIMAL.count @@ -34,13 +34,11 @@ func randomChar(from lexicon: [UInt8]) -> UInt8 { func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { - let len = UInt32(lexicon.count) - var pop = [[UInt8]]() - for _ in 0.. Int { - var fitness = 0 - for c in 0...dna.count-1 { + (0...dna.count-1).forEach { c in fitness += abs(Int(dna[c]) - Int(optimal[c])) } return fitness } -calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray) - -func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { +func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { let total = items.reduce(0.0) { return $0 + $1.weight} var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 - for itemTuple in items { - if n < itemTuple.weight { - return itemTuple + for item in items { + if n < item.weight { + return item } - n = n - itemTuple.weight + n = n - item.weight } return items[1] } @@ -80,7 +73,7 @@ func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], wei func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna - for i in 0..?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray +let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".unicodeArray // This is the end goal and what we will be using to rate fitness. In the real world this will not exist -let OPTIMAL:[UInt8] = "Hello, World".asciiArray +let OPTIMAL:[UInt8] = "Hello, World".unicodeArray // The length of the string in our population. Organisms need to be similar let DNA_SIZE = OPTIMAL.count @@ -34,45 +34,38 @@ func randomChar(from lexicon: [UInt8]) -> UInt8 { func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { - let len = UInt32(lexicon.count) - - var pop = [[UInt8]]() - - for _ in 0.. Int { - var fitness = 0 - for c in 0...dna.count-1 { + (0...dna.count-1).forEach { c in fitness += abs(Int(dna[c]) - Int(optimal[c])) } return fitness } -calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray) - -func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { +func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { let total = items.reduce(0.0) { return $0 + $1.weight} var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 - for itemTuple in items { - if n < itemTuple.weight { - return itemTuple + for item in items { + if n < item.weight { + return item } - n = n - itemTuple.weight + n = n - item.weight } return items[1] } @@ -80,7 +73,7 @@ func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], wei func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna - for i in 0.. Date: Fri, 9 Mar 2018 16:05:03 -0600 Subject: [PATCH 070/327] MAX_GENERATIONS --- Genetic/gen.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Genetic/gen.swift b/Genetic/gen.swift index aad499d04..a61e61785 100644 --- a/Genetic/gen.swift +++ b/Genetic/gen.swift @@ -21,7 +21,7 @@ let DNA_SIZE = OPTIMAL.count let POP_SIZE = 50 // max number of generations, script will stop when it reach 5000 if the optimal value is not found -let GENERATIONS = 5000 +let MAX_GENERATIONS = 5000 // The chance in which a random nucleotide can mutate (1/n) let MUTATION_CHANCE = 100 @@ -100,7 +100,7 @@ func main() { // print("population: \(population), dnaSize: \(DNA_SIZE) ") var fittest = [UInt8]() - for generation in 0...GENERATIONS { + for generation in 0...MAX_GENERATIONS { var weightedPopulation = [(dna:[UInt8], weight:Double)]() From 1bc39d21853c4fe869a6861354c54d213cd624bf Mon Sep 17 00:00:00 2001 From: Philip Ridgeway Date: Sat, 10 Mar 2018 10:57:39 -0800 Subject: [PATCH 071/327] Replaces references to indexOf(_:) with index(of:). The global function `indexOf(_:)` was replaced with `Collection.index(of:)` in Swift 2. --- Binary Search/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Binary Search/README.markdown b/Binary Search/README.markdown index 09b141e04..0cecce6cf 100644 --- a/Binary Search/README.markdown +++ b/Binary Search/README.markdown @@ -4,15 +4,15 @@ Goal: Quickly find an element in an array. Let's say you have an array of numbers and you want to determine whether a specific number is in that array, and if so, at which index. -In most cases, Swift's `indexOf()` function is good enough for that: +In most cases, Swift's `Collection.index(of:)` function is good enough for that: ```swift let numbers = [11, 59, 3, 2, 53, 17, 31, 7, 19, 67, 47, 13, 37, 61, 29, 43, 5, 41, 23] -numbers.indexOf(43) // returns 15 +numbers.index(of: 43) // returns 15 ``` -The built-in `indexOf()` function performs a [linear search](../Linear%20Search/). In code that looks something like this: +The built-in `Collection.index(of:)` function performs a [linear search](../Linear%20Search/). In code that looks something like this: ```swift func linearSearch(_ a: [T], _ key: T) -> Int? { From 0bcbd08988c5ab000a9901c6a6c03ab1a29aed6a Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 11 Mar 2018 12:59:19 -0700 Subject: [PATCH 072/327] Grammar fixes for first bit. --- Myers Difference Algorithm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index 2f6c3c579..a9d92a227 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -1,6 +1,6 @@ # Myers Difference Algorithm -Myers Difference Algorithm is the algorithm to find a longest common subsequence or shortest edit scripts (LCS/SES dual probrem) of two sequences by a simple O(ND) time, where N is the sum of the lengths of the two sequences. Common subsequence is the sequence of elements that appear in the same order in both sequences. Edit script will be discussed below. +Myers Difference Algorithm is an algorithm that finds a longest common subsequence or shortest edit scripts (LCS/SES dual probrem) of two sequences. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. The edit scripts will be discussed below. For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2", "3", "4"]`, `["2"], ["2", "3"]` are common sequences. Furthermore, the latter `["2", "3"]` is the longest common subsequence. But `["1", "2"], ["3", "2"]` are not. Because, `["1", "2"]` contains `"1"` that is not included in `B`, `["3", "2"]` has elements are included in both, but the appearing order is not correct. From 90afdf77d5fe66f20f1d68f38c9cf24d8070f363 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 11 Mar 2018 13:07:53 -0700 Subject: [PATCH 073/327] Couple more edits. --- Myers Difference Algorithm/README.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index a9d92a227..c1aa2da3a 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -1,20 +1,32 @@ # Myers Difference Algorithm -Myers Difference Algorithm is an algorithm that finds a longest common subsequence or shortest edit scripts (LCS/SES dual probrem) of two sequences. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. The edit scripts will be discussed below. +Myers Difference Algorithm is an algorithm that finds a longest common subsequence(LCS) or shortest edit scripts(SES) of two sequences. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. -For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2", "3", "4"]`, `["2"], ["2", "3"]` are common sequences. Furthermore, the latter `["2", "3"]` is the longest common subsequence. But `["1", "2"], ["3", "2"]` are not. Because, `["1", "2"]` contains `"1"` that is not included in `B`, `["3", "2"]` has elements are included in both, but the appearing order is not correct. +For example, let's assume you have two arrays: + +``` +A = [1, 2, 3] +B = [2, 3, 4] +``` + +The common subsequences of these two arrays are `[2]`, and `[2,3]`. The longest common sequence in this case is `[2,3]`. ## Finding the length of the Longest Common Subsequence with Myers Algorithm on Edit Graph ### Edit Graph -Myers Algorithm uses Edit Graph for solving LCS/SES problem. Edit Graph is the graph like below. +MDA uses an **Edit Graph** to solve the LCS/SES problem. Below is a illustration depicting an edit graph: -Here, we think about the length of the LCS of sequences `X = [A, B, C, A, B, B, A]`, `Y = [C, B, A, B, A, C]`. +In this case, the arrays are: + +``` +X = [A, B, C, A, B, B, A] +Y = [C, B, A, B, A, C] +``` -In Myers Algorithm, edit graph are prepared by +MDA generates the edit graph through the following steps: 1. Line the element of sequence `X` on the x axis. And do for `Y` on the y axis. 2. Make grid and vertex at each point in the grid (x, y), `x in [0, N] and y in [0, M]`. `N` is the length of sequence `X`, `M` is of `Y` From 38966972f6a602cb1a855d674bae58197af14c77 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 11 Mar 2018 13:11:57 -0700 Subject: [PATCH 074/327] Few more updates to the edit graph. --- Myers Difference Algorithm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index c1aa2da3a..6c242de88 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -19,7 +19,7 @@ MDA uses an **Edit Graph** to solve the LCS/SES problem. Below is a illustration -In this case, the arrays are: +The x-axis at the top of the graph represents one of the sequences, `X`. The y-axis at the left side of the graph represents the other sequence, `Y`. Hence, the two sequences in question is the following: ``` X = [A, B, C, A, B, B, A] From 81534d54a2f890ab1a5032941e77838b5e585d4b Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Wed, 14 Mar 2018 09:46:07 -0700 Subject: [PATCH 075/327] Update README.markdown --- Brute-Force String Search/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Brute-Force String Search/README.markdown b/Brute-Force String Search/README.markdown index 4e967bcfb..599fe75ea 100644 --- a/Brute-Force String Search/README.markdown +++ b/Brute-Force String Search/README.markdown @@ -51,6 +51,6 @@ extension String { This looks at each character in the source string in turn. If the character equals the first character of the search pattern, then the inner loop checks whether the rest of the pattern matches. If no match is found, the outer loop continues where it left off. This repeats until a complete match is found or the end of the source string is reached. -The brute-force approach works OK, but it's not very efficient (or pretty). It should work fine on small strings, though. For a smarter algorithm that works better with large chunks of text, check out [Boyer-Moore](../Boyer-Moore/) string search. +The brute-force approach works OK, but it's not very efficient (or pretty). It should work fine on small strings, though. For a smarter algorithm that works better with large chunks of text, check out [Boyer-Moore](../Boyer-Moore-Horspool) string search. *Written for Swift Algorithm Club by Matthijs Hollemans* From 2d5d8d0f552044b54b61409a46bd5b007f2fd2a2 Mon Sep 17 00:00:00 2001 From: James Lawson Date: Sun, 18 Mar 2018 10:00:41 +0000 Subject: [PATCH 076/327] Add Sparse Table link to README --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 5706fc8e5..dc0fc1f57 100644 --- a/README.markdown +++ b/README.markdown @@ -162,6 +162,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - [Segment Tree](Segment%20Tree/). Can quickly compute a function over a portion of an array. - [Lazy Propagation](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Segment%20Tree/LazyPropagation) - kd-Tree +- [Sparse Table](Sparse%20Table/). Another take on quickly computing a function over a portion of an array, but this time we'll make it even quicker!. - [Heap](Heap/). A binary tree stored in an array, so it doesn't use pointers. Makes a great priority queue. - Fibonacci Heap - [Trie](Trie/). A special type of tree used to store associative data structures. From 39da67cf7f5124fd3e5d270ea59361d86c512d78 Mon Sep 17 00:00:00 2001 From: Mike R Date: Sun, 25 Mar 2018 12:41:35 +0300 Subject: [PATCH 077/327] change function name for future code explanations --- Binary Search Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index 84e278f5c..30dc8d922 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -375,7 +375,7 @@ As an exercise, see if you can implement filter and reduce. We can make the code more readable by defining some helper functions. ```swift - private func reconnectParentToNode(node: BinarySearchTree?) { + private func reconnectParentTo(node: BinarySearchTree?) { if let parent = parent { if isLeftChild { parent.left = node From 8baf3549e597edbef432218eb3b52469a75c9df9 Mon Sep 17 00:00:00 2001 From: Daniel Strobusch <1847260+dastrobu@users.noreply.github.com> Date: Sun, 25 Mar 2018 18:23:11 +0200 Subject: [PATCH 078/327] fixed typo --- DiningPhilosophers/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index ae84cb63b..cd9d86154 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -44,7 +44,7 @@ Based on the Chandy and Misra's analysis, a system of preference levels is deriv # Swift implementation -This Swift 3.0 implementation of the Chandy/Misra solution is based on the GCD and Semaphore tecnique that can be built on both macOS and Linux. +This Swift 3.0 implementation of the Chandy/Misra solution is based on the GCD and Semaphore technique that can be built on both macOS and Linux. The code is based on a ForkPair struct used for holding an array of DispatchSemaphore and a Philosopher struct for associate a couple of forks to each Philosopher. From e4ce8d3f2894745ec4bd62d6fed82311bbe685ea Mon Sep 17 00:00:00 2001 From: James Lawson Date: Wed, 28 Mar 2018 19:21:44 +0100 Subject: [PATCH 079/327] Add Sparse Table --- Sparse Table/Images/idempotency.png | Bin 0 -> 33715 bytes Sparse Table/Images/query.png | Bin 0 -> 25405 bytes Sparse Table/Images/query_example.png | Bin 0 -> 29984 bytes Sparse Table/Images/recursion.png | Bin 0 -> 78302 bytes Sparse Table/Images/recursion_examples.png | Bin 0 -> 120693 bytes Sparse Table/Images/structure.png | Bin 0 -> 100125 bytes Sparse Table/Images/structure_examples.png | Bin 0 -> 157486 bytes Sparse Table/README.markdown | 310 ++++++++++++++++++ .../Sparse Table.playground/Contents.swift | 144 ++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + 11 files changed, 465 insertions(+) create mode 100644 Sparse Table/Images/idempotency.png create mode 100644 Sparse Table/Images/query.png create mode 100644 Sparse Table/Images/query_example.png create mode 100644 Sparse Table/Images/recursion.png create mode 100644 Sparse Table/Images/recursion_examples.png create mode 100644 Sparse Table/Images/structure.png create mode 100644 Sparse Table/Images/structure_examples.png create mode 100644 Sparse Table/README.markdown create mode 100644 Sparse Table/Sparse Table.playground/Contents.swift create mode 100644 Sparse Table/Sparse Table.playground/contents.xcplayground create mode 100644 Sparse Table/Sparse Table.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Sparse Table/Images/idempotency.png b/Sparse Table/Images/idempotency.png new file mode 100644 index 0000000000000000000000000000000000000000..88c8e7a8dd139bdea915c3f64c47493479cd6ea5 GIT binary patch literal 33715 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 {Su)c6b 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

    #kdl?Pj>dEBovu3p&qqx3XIy)t;_0 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 literal 0 HcmV?d00001 diff --git a/Sparse Table/Images/recursion.png b/Sparse Table/Images/recursion.png new file mode 100644 index 0000000000000000000000000000000000000000..6928e372cd91d89baee0f7f913a951610def165a GIT binary patch literal 78302 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 z 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 E0G7IR?EnA( literal 0 HcmV?d00001 diff --git a/Sparse Table/Images/recursion_examples.png b/Sparse Table/Images/recursion_examples.png new file mode 100644 index 0000000000000000000000000000000000000000..737b95bf98062013a062852644f422deb22e4ab2 GIT binary patch literal 120693 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 &Sk;n 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

  • MsS%*de4F$i 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 T#dl#?wN$E#8mF^Qn)>_;z7a~d literal 0 HcmV?d00001 diff --git a/Sparse Table/Images/structure_examples.png b/Sparse Table/Images/structure_examples.png new file mode 100644 index 0000000000000000000000000000000000000000..69fd57218d86589ade8207b92755707549365b76 GIT binary patch literal 157486 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 s=l`d;|E|RUQ`~>o$p2S8?)dSk*7cJ5Uha[\*]. The function can be: min, max, [gcd](../GCD/), boolean AND, boolean OR ... + +*[\*] where **f** is also "idempotent". Don't worry, I'll explain this in a moment.* + +Our task is as follows: + +- Given two indices **l** and **r**, answer a **query** for the interval `[l, r)` by performing `f(a[l], a[l + 1], a[l + 2], ..., a[r - 1])`; taking all the elements in the range and applying **f** to them +- There will be a *huge* number **Q** of these queries to answer ... so we should be able to answer each query *quickly*! + +For example, if we have an array of numbers: + +```swift +var a = [ 20, 3, -1, 101, 14, 29, 5, 61, 99 ] +``` +and our function **f** is the *min* function. + +Then we may be given a query for interval `[3, 8)`. That means we look at the elements: + +``` +101, 14, 29, 5, 61 +``` + +because these are the elements of **a** with indices +that lie in our range `[3, 8)` – elements from index 3 up to, but not including, index 8. +We then we pass all of these numbers into the min function, +which takes the minimum. The answer to the query is `5`, because that's the result of `min(101, 14, 29, 5, 61)`. + +Imagine we have millions of these queries to process. +> - *Query 1*: Find minimum of all elements between 2 and 5 +> - *Query 2*: Find minimum of all elements between 3 and 9 +> - ... +> - *Query 1000000*: Find minimum of all elements between 1 and 4 + +And our array is very large. Here, let's say **Q** = 1000000 and **N** = 500000. Both numbers are *huge*. We want to make sure that we can answer each query really quickly, or else the number of queries will overwhelm us! + +*So that's the problem.* + +The naive solution to this problem is to perform a `for` loop +to compute the answer for each query. However, for very large **Q** and very large **N** this +will be too slow. We can speed up the time to compute the answer by using a data structure called +a **Sparse Table**. You'll notice that so far, our problem is exactly the same as that of the [Segment Tree](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Segment%20Tree) +(assuming you're familiar). However! ... there's one crucial difference between Segment Trees +and Sparse Tables ... and it concerns our choice of **f**. + + +### A small gotcha ... Idempotency + +Suppose we wanted to find the answer to **`[A, D)`**. +And we already know the answer to two ranges **`[A, B)`** and **`[C, D)`**. +And importantly here, ... *these ranges overlap*!! We have **C** < **B**. + +![Overlapping ranges](Images/idempotency.png) + + +So what? Well, for **f** = minimum function, we can take our answers for **`[A, B)`** and **`[C, D)`** +and combine them! +We can just take the minimum of the two answers: `result = min(x1, x2)` ... *voilà!*, we have the minimum for **`[A, D)`**. +It didn't matter that the intervals overlap - we still found the correct minimum. +But now suppose **f** is the addition operation `+`. Ok, so now we're taking sums over ranges. +If we tried the same approach again, it wouldn't work. That is, +if we took our answers for **`[A, B)`** and **`[C, D)`** +and added them together we'd get a wrong answer for **`[A, D)`**. +*Why?* Well, we'd have counted some elements twice because of the overlap. + +Later, we'll see that in order to answer queries, Sparse Tables use this very technique. +They combine answers in the same way as shown above. Unfortunately this means +we have to exclude certain binary operators from being **f**, including `+`, `*`, XOR, ... +because they don't work with this technique. +In order to get the best speed of a Sparse Table, +we need to make sure that the **f** we're using is an **[idempotent](https://en.wikipedia.org/wiki/Idempotence)** binary operator. +Mathematically, these are operators that satisfy `f(x, x) = x` for all possible **x** that could be in **a**. +Practically speaking, these are the only operators that work; allowing us to combine answers from overlapping ranges. +Examples of idempotent **f**'s are min, max, gcd, boolean AND, boolean OR, bitwise AND and bitwise OR. +Note that for Segment Trees, **f** does not have to be idempotent. That's the crucial difference between +Segment Trees and Sparse Tables. + +*Phew!* Now that we've got that out of the way, let's dive in! + +## Structure of a Sparse Table + +Let's use **f** = min and use the array: + +```swift +var a = [ 10, 6, 5, -7, 9, -8, 2, 4, 20 ] +``` + +In this case, the Sparse Table looks like this: + +![Sparse Table](Images/structure.png) + +What's going on here? There seems to be loads of intervals. +*Correct!* Sparse tables are preloaded with the answers for lots of queries `[l, r)`. +Here's the idea. Before we process our **Q** queries, we'll pre-populate our Sparse Table `table` +with answers to loads of queries; +making it act a bit like a *cache*. When we come to answer one of our queries, we can break the query +down into smaller "sub-queries", each having an answer that's already in the cache. +We lookup the cached answers for the sub-queries in +`table` in constant time +and combine the answers together +to give the overall answer to the original query in speedy time. + +The problem is, we can't store the answers for every single possible query that we could ever have ... +or else our table would be too big! After all, our Sparse Table needs to be *sparse*. So what do we do? +We only pick the "best" intervals to store answers for. And as it turns out, the "best" intervals are those +that have a **width that is a power of two**! + +For example, the answer for the query `[10, 18)` is in our table +because the interval width: `18 - 10 = 8 = 2**3` is a power of two (`**` is the [exponentiation operator](https://en.wikipedia.org/wiki/Exponentiation)). +Also, the answer for `[15, 31)` is in our table because its width: `31 - 15 = 16 = 2**4` is again a power of two. +However, the answer for `[1, 6)` is *not* in there because the interval's width: `6 - 1 = 5` is *not* a power of two. +Consequently, we don't store answers for *all* possible intervals that fit inside **a** – +only the ones with a width that is a power of two. +This is true irrespective of where the interval starts within **a**. +We'll gradually see that this approach works and that relatively speaking, it uses very little space. + +A **Sparse Table** is a table where `table[w][l]` contains the answer for `[l, l + 2**w)`. +It has entries `table[w][l]` where: +- **w** tells us our **width** ... the number of elements or the *width* is `2**w` +- **l** tells us the **lower bound** ... it's the starting point of our interval + +Some examples: +- `table[3][0] = -8`: our width is `2**3`, we start at `l = 0` so our query is `[0, 0 + 2**3) = [0, 8)`. + The answer for this query is `min(10, 6, 5, -7, 9, -8, 2, 4, 20) = -8`. +- `table[2][1] = -7`: our width is `2**2`, we start at `l = 1` so our query is `[1, 1 + 2**2) = [1, 5)`. + The answer for this query is `min(6, 5, -7, 9) = -7`. +- `table[1][7] = 4`: our width is `2**1`, we start at `l = 7` so our query is `[7, 7 + 2**1) = [7, 9)`. + The answer for this query is `min(4, 20) = 4`. +- `table[0][8] = 20`: our width is `2**0`, we start at `l = 8` so our query is`[8, 8 + 2**0) = [8, 9)`. + The answer for this query is `min(20) = 20`. + + +![Sparse Table](Images/structure_examples.png) + + +A Sparse Table can be implemented using a [two-dimentional array](../2D%20Array). + +```swift +public class SparseTable { + private var table: [[T]] + + public init(array: [T], function: @escaping (T, T) -> T, defaultT: T) { + table = [[T]](repeating: [T](repeating: defaultT, count: N), count: W) + } + // ... +} +``` + + +## Building a Sparse Table + +To build a Sparse Table, we compute each table entry starting from the bottom-left and moving up towards +the top-right (in accordance with the diagram). +First we'll compute all the intervals for **w** = 0, then compute all the intervals +and for **w** = 1 and so on. We'll continue up until **w** is big enough such that our intervals are can cover at least half the array. +For each **w**, we compute the interval for **l** = 0, 1, 2, 3, ... until we reach **N**. +This is all achieved using a double `for`-`in` loop: + +```swift +for w in 0.. 0)**: We need to find out the answer to `[l, l + 2**w)` for some **l**. +This interval, like all of our intervals in our table has a width that +is a power of two (e.g. 2, 4, 8, 16) ... so we can cut it into two equal halves. + - Our interval with width ``2**w`` is cut into two intervals, each of width ``2**(w - 1)``. + - Because each half has a width that is a power of two, we can look them up in our Sparse Table. + - We combine them together using **f**. + ``` + table[w][l] = f(table[w - 1][l], table[w - 1][l + 2 ** (w - 1)]) + ``` + + +![Sparse Table](Images/recursion.png) + +For example for `a = [ 10, 6, 5, -7, 9, -8, 2, 4, 20 ]` and **f** = *min*: + +- we compute `table[0][2] = 5`. We just had to look at `a[2]` because the range has a width of one. +- we compute `table[1][7] = 4`. We looked at `table[0][7]` and `table[0][8]` and apply **f** to them. +- we compute `table[3][1] = -8`. We looked at `table[2][1]` and `table[2][5]` and apply **f** to them. + + +![Sparse Table](Images/recursion_examples.png) + + + +```swift +public init(array: [T], function: @escaping (T, T) -> T, defaultT: T) { + let N = array.count + let W = Int(ceil(log2(Double(N)))) + table = [[T]](repeating: [T](repeating: defaultT, count: N), count: W) + self.function = function + self.defaultT = defaultT + + for w in 0.. T { + let width = r - l + let W = Int(floor(log2(Double(width)))) + let lo = table[W][l] + let hi = table[W][r - (1 << W)] + return function(lo, hi) + } + ``` + +Finding answers to queries takes **O(1)** time. + +## Analysing Sparse Tables + +- **Query Time** - Both table lookups take constant time. All other operations inside `query` take constant time. +So answering a single query also takes constant time: **O(1)**. But instead of one query we're actually answering **Q** queries, +and we'll need time to built the table before-hand. +Overall time is: **O(NlgN + Q)** to build the table and answer all queries. +The naive approach is to do a for loop for each query. The overall time for the naive approach is: **O(NQ)**. +For very large **Q**, the naive approach will scale poorly. For example if `Q = O(N*N)` +then the naive approach is `O(N*N*N)` where a Sparse Table takes time `O(N*N)`. +- **Space**- The number of possible **w** is **lgN** and the number of possible **i** our table is **N**. So the table +has uses **O(NlgN)** additional space. + +### Comparison with Segment Trees + +- **Pre-processing** - Segment Trees take **O(N)** time to build and use **O(N)** space. Sparse Tables take **O(NlgN)** time to build and use **O(NlgN)** space. +- **Queries** - Segment Tree queries are **O(lgN)** time for any **f** (idempotent or not idempotent). Sparse Table queries are **O(1)** time if **f** is idempotent and are not supported if **f** is not idempotent. [†] +- **Replacing Items** - Segment Trees allow us to efficiently update an element in **a** and update the segment tree in **O(lgN)** time. Sparse Tables do not allow this to be done efficiently. If we were to update an element in **a**, we'd have to rebuild the Sparse Table all over again in **O(NlgN)** time. + + +[†] *Although technically, it's possible to rewrite the `query` method +to add support for non-idempotent functions. But in doing so, we'd bump up the time up from O(1) to O(lgn), +completely defeating the original purpose of Sparse Tables - supporting lightening quick queries. +In such a case, we'd be better off using a Segment Tree (or a Fenwick Tree)* + +## Summary + +That's it! See the playground for more examples involving Sparse Tables. +You'll see examples for: min, max, gcd, boolean operators and logical operators. + +### See also + +- [Segment Trees (Swift Algorithm Club)](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Segment%20Tree) +- [How to write O(lgn) time query function to support non-idempontent functions (GeeksForGeeks)](https://www.geeksforgeeks.org/range-sum-query-using-sparse-table/) +- [Fenwick Trees / Binary Indexed Trees (TopCoder)](https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/) +- [Semilattice (Wikipedia)](https://en.wikipedia.org/wiki/Semilattice) + +*Written for Swift Algorithm Club by [James Lawson](https://github.com/jameslawson)* + diff --git a/Sparse Table/Sparse Table.playground/Contents.swift b/Sparse Table/Sparse Table.playground/Contents.swift new file mode 100644 index 000000000..4eae8a6c2 --- /dev/null +++ b/Sparse Table/Sparse Table.playground/Contents.swift @@ -0,0 +1,144 @@ +// +// Swift Algorithm Club - Sparse Table +// Author: James Lawson (github.com/jameslawson) +// + +import Foundation + +// Last checked with Xcode Version 9.2 (9C40b) +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + +public class SparseTable { + private var defaultT: T + private var table: [[T]] + private var function: (T, T) -> T + + public init(array: [T], function: @escaping (T, T) -> T, defaultT: T) { + let N = array.count + let W = Int(ceil(log2(Double(N)))) + table = [[T]](repeating: [T](repeating: defaultT, count: N), count: W) + self.function = function + self.defaultT = defaultT + + for w in 0.. T { + let width = r - l + let N = table[0].count + if width <= 0 || l >= N { + return defaultT + } + let r = min(N, r) + let W = Int(floor(log2(Double(width)))) + let lo = table[W][l] + let hi = table[W][r - (1 << W)] + return function(lo, hi) + } +} + +print("---------------------------- EXAMPLE 1 -------------------------------------") +// Here we have an array of integers and we're repeatedly +// finding the minimum over various ranges + +let intArray = [1, -11, -7, 3, 2, 4] +let minIntTable = SparseTable(array: intArray, function: min, defaultT: Int.max) +print(minIntTable.query(from: 0, until: 6)) // min(1, 3, -11, 3, 2, 4) = -11 +print(minIntTable.query(from: 3, until: 5)) // min(3, 2) = 2 +print(minIntTable.query(from: 2, until: 6)) // min(-7, 3, 2, 4) = -7 +print(minIntTable.query(from: 0, until: 1)) // min(1) = 1 +print(minIntTable.query(from: 0, until: 0)) // min() = Int.max +print("----------------------------------------------------------------------------\n\n") + + +print("---------------------------- EXAMPLE 2 -------------------------------------") +// Now we have an array of doubles and we're repeatedly +// finding the maximum over various ranges + +let doubleArray = [1.5, 20.0, 3.5, 15.0, 18.0, -10.0, 5.5] +let maxDoubleTable = SparseTable(array: doubleArray, function: max, defaultT: -.infinity) +print(maxDoubleTable.query(from: 0, until: 4)) // max(1.5, 20.0, 3.5, 15.0) = 20.0 +print(maxDoubleTable.query(from: 3, until: 4)) // max(3.5, 15.0) = 15.0 +print(maxDoubleTable.query(from: 4, until: 6)) // max(18.0, -10.0, 5.5) = 18.0 +print(maxDoubleTable.query(from: 1, until: 2)) // max(20.0) = 20.0 +print(maxDoubleTable.query(from: 0, until: 0)) // max() = -inf +print("----------------------------------------------------------------------------\n\n") + + +print("---------------------------- EXAMPLE 3 -------------------------------------") +// An array of booleans and we're repeatedly +// finding the boolean AND over various ranges + +let boolArray = [true, false, true, true, true, false, false] +func and(_ x: Bool, _ y: Bool) -> Bool { return x && y } + +let maxBoolTable = SparseTable(array: boolArray, function: and, defaultT: false) +print(maxBoolTable.query(from: 0, until: 4)) // and(T, F, T, T) = F +print(maxBoolTable.query(from: 2, until: 5)) // and(T, T, T) = T +print(maxBoolTable.query(from: 2, until: 6)) // and(T, T, T, F) = F +print(maxBoolTable.query(from: 0, until: 1)) // and(T) = T +print(maxBoolTable.query(from: 1, until: 2)) // and(F) = F +print(maxBoolTable.query(from: 0, until: 0)) // and() = F +print("----------------------------------------------------------------------------\n\n") + +print("---------------------------- EXAMPLE 4 -------------------------------------") +// An array of positive integers and we're repeatedly finding +// the gcd (greatest common divisor) over various ranges. The gcd operator is +// associative and idempontent so we can use it with sparse tables + +let posIntArray = [7, 2, 3, 4, 6, 5, 25, 75, 100] +func gcd(_ m: Int, _ n: Int) -> Int { + var a = 0 + var b = max(m, n) + var r = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } + return b +} + +let gcdTable = SparseTable(array: posIntArray, function: gcd, defaultT: 1) +print(gcdTable.query(from: 0, until: 4)) // gcd(7, 2, 3) = 1 +print(gcdTable.query(from: 3, until: 5)) // gcd(4, 6) = 2 +print(gcdTable.query(from: 5, until: 7)) // gcd(5, 25, 75) = 5 +print(gcdTable.query(from: 6, until: 9)) // gcd(25, 75, 100) = 25 +print(gcdTable.query(from: 3, until: 4)) // gcd(4) = 4 +print(gcdTable.query(from: 0, until: 0)) // gcd() = 1 +print("------------------------------------------------------------------------\n\n") + + + +print("---------------------------- EXAMPLE 5 -------------------------------------") +// An array of nonnegative integers where for each integer we consider its binary representation. +// We're repeatedly finding the binary OR (|) over various ranges. The binary operator is +// associative and idempontent so we can use it with sparse tables + +let binArray = [0b1001, 0b1100, 0b0000, 0b0001, 0b0010, 0b0100, 0b0000, 0b1111] + + +let orTable = SparseTable(array: binArray, function: |, defaultT: 0b0000) +print(String(orTable.query(from: 0, until: 2), radix: 2)) // binary_or(1001, 1100) = 1101 +print(String(orTable.query(from: 3, until: 5), radix: 2)) // binary_or(0001, 0010) = 0011 + +print(String(orTable.query(from: 3, until: 6), radix: 2)) // binary_or(0001, 0010, 0100) = 0111 +print(String(orTable.query(from: 6, until: 8), radix: 2)) // binary_or(0000, 1111) = 1111 +print(String(orTable.query(from: 1, until: 5), radix: 2)) // binary_or(1100, 0000, 0001, 0010) = 1111 +print(String(orTable.query(from: 0, until: 1), radix: 2)) // binary_or(1001) = 1001 +print(String(orTable.query(from: 0, until: 0), radix: 2)) // binary_or() = 0000 +print("----------------------------------------------------------------------------\n\n") diff --git a/Sparse Table/Sparse Table.playground/contents.xcplayground b/Sparse Table/Sparse Table.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Sparse Table/Sparse Table.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Sparse Table/Sparse Table.playground/playground.xcworkspace/contents.xcworkspacedata b/Sparse Table/Sparse Table.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Sparse Table/Sparse Table.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + From 7d759ee1a1b2983fb887e514341509842a26a60d Mon Sep 17 00:00:00 2001 From: James Lawson Date: Wed, 28 Mar 2018 19:29:45 +0100 Subject: [PATCH 080/327] Fix typo. Rename varaible from i to l --- Sparse Table/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sparse Table/README.markdown b/Sparse Table/README.markdown index 701a33f21..31bd5a781 100644 --- a/Sparse Table/README.markdown +++ b/Sparse Table/README.markdown @@ -279,7 +279,7 @@ Overall time is: **O(NlgN + Q)** to build the table and answer all queries. The naive approach is to do a for loop for each query. The overall time for the naive approach is: **O(NQ)**. For very large **Q**, the naive approach will scale poorly. For example if `Q = O(N*N)` then the naive approach is `O(N*N*N)` where a Sparse Table takes time `O(N*N)`. -- **Space**- The number of possible **w** is **lgN** and the number of possible **i** our table is **N**. So the table +- **Space**- The number of possible **w** is **lgN** and the number of possible **l** our table is **N**. So the table has uses **O(NlgN)** additional space. ### Comparison with Segment Trees From 11a5e7cb24279b86da99c8ffcd791c2bbfbe6b58 Mon Sep 17 00:00:00 2001 From: James Lawson Date: Wed, 28 Mar 2018 19:33:16 +0100 Subject: [PATCH 081/327] Fix typo "Idempotent" --- Sparse Table/Sparse Table.playground/Contents.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Sparse Table/Sparse Table.playground/Contents.swift b/Sparse Table/Sparse Table.playground/Contents.swift index 4eae8a6c2..ef83263b0 100644 --- a/Sparse Table/Sparse Table.playground/Contents.swift +++ b/Sparse Table/Sparse Table.playground/Contents.swift @@ -14,14 +14,14 @@ public class SparseTable { private var defaultT: T private var table: [[T]] private var function: (T, T) -> T - + public init(array: [T], function: @escaping (T, T) -> T, defaultT: T) { let N = array.count let W = Int(ceil(log2(Double(N)))) table = [[T]](repeating: [T](repeating: defaultT, count: N), count: W) self.function = function self.defaultT = defaultT - + for w in 0.. { } } } - + public func query(from l: Int, until r: Int) -> T { let width = r - l let N = table[0].count @@ -97,14 +97,14 @@ print("------------------------------------------------------------------------- print("---------------------------- EXAMPLE 4 -------------------------------------") // An array of positive integers and we're repeatedly finding // the gcd (greatest common divisor) over various ranges. The gcd operator is -// associative and idempontent so we can use it with sparse tables +// associative and idempotent so we can use it with sparse tables let posIntArray = [7, 2, 3, 4, 6, 5, 25, 75, 100] func gcd(_ m: Int, _ n: Int) -> Int { var a = 0 var b = max(m, n) var r = min(m, n) - + while r != 0 { a = b b = r @@ -127,7 +127,7 @@ print("------------------------------------------------------------------------\ print("---------------------------- EXAMPLE 5 -------------------------------------") // An array of nonnegative integers where for each integer we consider its binary representation. // We're repeatedly finding the binary OR (|) over various ranges. The binary operator is -// associative and idempontent so we can use it with sparse tables +// associative and idempotent so we can use it with sparse tables let binArray = [0b1001, 0b1100, 0b0000, 0b0001, 0b0010, 0b0100, 0b0000, 0b1111] From eda68c40eba5aef49b3f23b8fccf9bab62eb6e9d Mon Sep 17 00:00:00 2001 From: Stephen Clark Date: Fri, 30 Mar 2018 16:15:25 +0100 Subject: [PATCH 082/327] Convex Hull: Clarified Readme, and small code clarity changes. Began to clarify Convex Hull readme, and code. (Needs more work!!) --- .../Convex Hull.xcodeproj/project.pbxproj | 6 +++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Convex Hull/Convex Hull/View.swift | 12 ++---------- Convex Hull/README.md | 18 ++++++++++++++---- 4 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Convex Hull/Convex Hull.xcodeproj/project.pbxproj b/Convex Hull/Convex Hull.xcodeproj/project.pbxproj index 651a5bed3..c11cbf4d6 100644 --- a/Convex Hull/Convex Hull.xcodeproj/project.pbxproj +++ b/Convex Hull/Convex Hull.xcodeproj/project.pbxproj @@ -149,7 +149,7 @@ }; 8E6D68B51E59989400161780 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = 7C4LVS3ZVC; + DevelopmentTeam = 4SQG5NJNPF; ProvisioningStyle = Automatic; }; }; @@ -384,7 +384,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = 7C4LVS3ZVC; + DEVELOPMENT_TEAM = 4SQG5NJNPF; INFOPLIST_FILE = "Convex Hull/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "workmoose.Convex-Hull"; @@ -397,7 +397,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = 7C4LVS3ZVC; + DEVELOPMENT_TEAM = 4SQG5NJNPF; INFOPLIST_FILE = "Convex Hull/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "workmoose.Convex-Hull"; diff --git a/Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Convex Hull/Convex Hull.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Convex Hull/Convex Hull/View.swift b/Convex Hull/Convex Hull/View.swift index a50cc247a..33d1426c3 100644 --- a/Convex Hull/Convex Hull/View.swift +++ b/Convex Hull/Convex Hull/View.swift @@ -11,20 +11,12 @@ import UIKit class View: UIView { let MAX_POINTS = 100 - var points = [CGPoint]() - var convexHull = [CGPoint]() override init(frame: CGRect) { super.init(frame: frame) - - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - - generatePoints() + generateRandomPoints() quickHull(points: points) } @@ -32,7 +24,7 @@ class View: UIView { fatalError("init(coder:) has not been implemented") } - func generatePoints() { + func generateRandomPoints() { for _ in 0.. Date: Sat, 31 Mar 2018 14:12:06 +0530 Subject: [PATCH 083/327] Fixed broken youtube link in splay tree readme --- Splay Tree/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Splay Tree/readme.md b/Splay Tree/readme.md index f3b852f22..75c3c0389 100644 --- a/Splay Tree/readme.md +++ b/Splay Tree/readme.md @@ -263,7 +263,7 @@ If the rotations would had been taking first the parent and not the grandparent [Splay Tree on Wikipedia](https://en.wikipedia.org/wiki/Splay_tree) -[Splay Tree by University of California in Berkeley - CS 61B Lecture 34](https://www.youtube.com/watch?v=G5QIXywcJlY) +[Splay Tree by University of California in Berkeley - CS 61B Lecture 34](https://www.youtube.com/watch?v=8Zs1lj_bUV0) ---------------- From 3bf65574bf04db1e0540494ece247f2beba79a5c Mon Sep 17 00:00:00 2001 From: horita-yuya Date: Sat, 7 Apr 2018 03:30:09 +0900 Subject: [PATCH 084/327] add explanation --- Myers Difference Algorithm/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index 6c242de88..e6137e8ce 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -34,6 +34,11 @@ MDA generates the edit graph through the following steps: 3. Check the points `(i, j)`, where `X[i] = Y[j]`, called match point, light green one. 4. Connect vertex `(i - 1, j - 1)` and vertex `(i, j)`, where `(i, j)` is match point, then diagonal edge appears. +Each elements on the figure shows that, +- `Red number and dotted lines`: The red number is the value of k and dotted lines are k-line. +- `Green dots: The match points`, which is the point `(i, j)` where `X[i] == Y[j]` +- `Blue line`: The shortest path from source to sink, which is the path we are going to find finally. + > **Note:** Here, the sequences' start index is 1 not 0, so `X[1] = A`, `Y[1] = C` We discuss about which path is the shortest from `source` to `sink`. Can move on the edges on the graph. I mean we can move on the grid, horizontal and vertical edges, and the diagonal edges. From 6bf3a160912dd4b7bf91379175549321fd45cecc Mon Sep 17 00:00:00 2001 From: Jorge Date: Wed, 11 Apr 2018 19:17:12 +0200 Subject: [PATCH 085/327] Update Combinatorics to match Swift 4 API --- Combinatorics/README.markdown | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Combinatorics/README.markdown b/Combinatorics/README.markdown index b365b389b..a2432a680 100644 --- a/Combinatorics/README.markdown +++ b/Combinatorics/README.markdown @@ -99,17 +99,17 @@ Here's a recursive algorithm by Niklaus Wirth: ```swift func permuteWirth(_ a: [T], _ n: Int) { - if n == 0 { - print(a) // display the current permutation - } else { - var a = a - permuteWirth(a, n - 1) - for i in 0.. Date: Tue, 17 Apr 2018 08:46:31 -0400 Subject: [PATCH 086/327] Added link to Swift Alg Club book --- ...DataStructuresAndAlgorithmsInSwiftBook.png | Bin 0 -> 136406 bytes README.markdown | 26 ++++-------------- 2 files changed, 6 insertions(+), 20 deletions(-) create mode 100644 Images/DataStructuresAndAlgorithmsInSwiftBook.png diff --git a/Images/DataStructuresAndAlgorithmsInSwiftBook.png b/Images/DataStructuresAndAlgorithmsInSwiftBook.png new file mode 100644 index 0000000000000000000000000000000000000000..f8de0ba72754c0994ed31cbcd17304b791d91116 GIT binary patch literal 136406 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 DtMDZ~ literal 0 HcmV?d00001 diff --git a/README.markdown b/README.markdown index dc0fc1f57..481e25f62 100644 --- a/README.markdown +++ b/README.markdown @@ -206,32 +206,18 @@ A lot of software developer interview questions consist of algorithmic puzzles. - [Dining Philosophers](DiningPhilosophers/) - [Egg Drop Problem](Egg%20Drop%20Problem/) - [Encoding and Decoding Binary Tree](Encode%20and%20Decode%20Tree/) -## Learn more! -For more information, check out these great books: +## Learn more! -- [Introduction to Algorithms](https://mitpress.mit.edu/books/introduction-algorithms) by Cormen, Leiserson, Rivest, Stein -- [The Algorithm Design Manual](http://www.algorist.com) by Skiena -- [Elements of Programming Interviews](http://elementsofprogramminginterviews.com) by Aziz, Lee, Prakash -- [Algorithms](http://www.cs.princeton.edu/~rs/) by Sedgewick -- [Grokking Algorithms](https://www.manning.com/books/grokking-algorithms) by Aditya Bhargava +Like what you see? Check out [Data Structures & Algorithms in Swift](https://store.raywenderlich.com/products/data-structures-and-algorithms-in-swift), the official book by the Swift Algorithm Club team! -The following books are available for free online: +![Data Structures & Algorithms in Swift Book](Images/DataStructuresAndAlgorithmsInSwift.png) -- [Algorithms](http://www.beust.com/algorithms.pdf) by Dasgupta, Papadimitriou, Vazirani -- [Algorithms, Etc.](http://jeffe.cs.illinois.edu/teaching/algorithms/) by Erickson -- [Algorithms + Data Structures = Programs](http://www.ethoberon.ethz.ch/WirthPubl/AD.pdf) by Wirth -- Algorithms and Data Structures: The Basic Toolbox by Mehlhorn and Sanders -- [Open Data Structures](http://opendatastructures.org) by Pat Morin -- [Wikibooks: Algorithms and Implementations](https://en.wikibooks.org/wiki/Algorithm_Implementation) +You’ll start with the fundamental structures of linked lists, queues and stacks, and see how to implement them in a highly Swift-like way. Move on to working with various types of trees, including general purpose trees, binary trees, AVL trees, binary search trees, and tries. -Other algorithm repositories: +Go beyond bubble and insertion sort with better-performing algorithms, including mergesort, radix sort, heap sort, and quicksort. Learn how to construct directed, non-directed and weighted graphs to represent many real-world models, and traverse graphs and trees efficiently with breadth-first, depth-first, Dijkstra’s and Prim’s algorithms to solve problems such as finding the shortest path or lowest cost in a network. -- [EKAlgorithms](https://github.com/EvgenyKarkan/EKAlgorithms). A great collection of algorithms in Objective-C. -- [@lorentey](https://github.com/lorentey/). Production-quality Swift implementations of common algorithms and data structures. -- [Rosetta Code](http://rosettacode.org). Implementations in pretty much any language you can think of. -- [AlgorithmVisualizer](http://jasonpark.me/AlgorithmVisualizer/). Visualize algorithms on your browser. -- [Swift Structures](https://github.com/waynewbishop/SwiftStructures) Data Structures with directions on how to use them [here](http://waynewbishop.com/swift) +By the end of this book, you’ll have hands-on experience solving common issues with data structures and algorithms — and you’ll be well on your way to developing your own efficient and useful implementations! ## Credits From 8010ec629e93228bd960da271b406420d6cb9cb0 Mon Sep 17 00:00:00 2001 From: Ray Wenderlich Date: Tue, 17 Apr 2018 08:47:31 -0400 Subject: [PATCH 087/327] Fixed typo in link --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 481e25f62..783750fbc 100644 --- a/README.markdown +++ b/README.markdown @@ -211,7 +211,7 @@ A lot of software developer interview questions consist of algorithmic puzzles. Like what you see? Check out [Data Structures & Algorithms in Swift](https://store.raywenderlich.com/products/data-structures-and-algorithms-in-swift), the official book by the Swift Algorithm Club team! -![Data Structures & Algorithms in Swift Book](Images/DataStructuresAndAlgorithmsInSwift.png) +![Data Structures & Algorithms in Swift Book](Images/DataStructuresAndAlgorithmsInSwiftBook.png) You’ll start with the fundamental structures of linked lists, queues and stacks, and see how to implement them in a highly Swift-like way. Move on to working with various types of trees, including general purpose trees, binary trees, AVL trees, binary search trees, and tries. From 12471a2f8ed0586269c8cb693efc5a33e31c45c0 Mon Sep 17 00:00:00 2001 From: Ray Wenderlich Date: Tue, 17 Apr 2018 08:48:25 -0400 Subject: [PATCH 088/327] Added final link to book --- README.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.markdown b/README.markdown index 783750fbc..919f1b67f 100644 --- a/README.markdown +++ b/README.markdown @@ -219,6 +219,8 @@ Go beyond bubble and insertion sort with better-performing algorithms, including By the end of this book, you’ll have hands-on experience solving common issues with data structures and algorithms — and you’ll be well on your way to developing your own efficient and useful implementations! +You can find the book on the [raywenderlich.com store](https://store.raywenderlich.com/products/data-structures-and-algorithms-in-swift). + ## Credits The Swift Algorithm Club was originally created by [Matthijs Hollemans](https://github.com/hollance). From 730059ec7ba7dd16115f09d5d58a01b068df9beb Mon Sep 17 00:00:00 2001 From: APKaramyshev <38246803+APKaramyshev@users.noreply.github.com> Date: Sat, 21 Apr 2018 21:54:58 +0300 Subject: [PATCH 089/327] Fixed two misspellings in O(n!) example --- Big-O Notation.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Big-O Notation.markdown b/Big-O Notation.markdown index 19a1ddbde..257f80462 100644 --- a/Big-O Notation.markdown +++ b/Big-O Notation.markdown @@ -132,9 +132,9 @@ Below are some examples for each category of performance: The most trivial example of function that takes O(n!) time is given below. ```swift - func nFacFunc(n: Int) { + func nFactFunc(n: Int) { for i in stride(from: 0, to: n, by: 1) { - nFactFunc(n - 1) + nFactFunc(n: n - 1) } } ``` From a0cfcee54c015e1110ca7ab102d9ba84bda0ae85 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 22 Apr 2018 18:29:44 -0700 Subject: [PATCH 090/327] Update README.markdown --- Genetic/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index 07547c4b4..18afb9639 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -1,4 +1,4 @@ -individual# Genetic Algorthim +# Genetic Algorthim ## What is it? From 83b08626a172030777db1924513599ad55c32f34 Mon Sep 17 00:00:00 2001 From: Keith Date: Mon, 23 Apr 2018 15:31:04 +0800 Subject: [PATCH 091/327] Update README.markdown Here should be right. Bottom-left corner of the matrix is `matrix[0][m+1]` --- Longest Common Subsequence/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Longest Common Subsequence/README.markdown b/Longest Common Subsequence/README.markdown index 4cd2c2fcb..a62c562a6 100644 --- a/Longest Common Subsequence/README.markdown +++ b/Longest Common Subsequence/README.markdown @@ -99,7 +99,7 @@ And so on... this is how `lcsLength(_:)` fills in the entire matrix. ## Backtracking to find the actual subsequence -So far we've calculated the length of every possible subsequence. The length of the longest subsequence is found in the bottom-left corner of matrix, at `matrix[n+1][m+1]`. In the above example it is 4, so the LCS consists of 4 characters. +So far we've calculated the length of every possible subsequence. The length of the longest subsequence is found in the bottom-right corner of matrix, at `matrix[n+1][m+1]`. In the above example it is 4, so the LCS consists of 4 characters. Having the length of every combination of substrings makes it possible to determine *which* characters are part of the LCS itself by using a backtracking strategy. From e0c0200ba34960f7b48dc742a33fd2a966843a83 Mon Sep 17 00:00:00 2001 From: Keith Date: Mon, 23 Apr 2018 16:18:23 +0800 Subject: [PATCH 092/327] Update README.markdown Fix typo: top-right -> top-left --- Longest Common Subsequence/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Longest Common Subsequence/README.markdown b/Longest Common Subsequence/README.markdown index a62c562a6..8a4a763c6 100644 --- a/Longest Common Subsequence/README.markdown +++ b/Longest Common Subsequence/README.markdown @@ -156,7 +156,7 @@ func backtrack(_ matrix: [[Int]]) -> String { } ``` -This backtracks from `matrix[n+1][m+1]` (bottom-right corner) to `matrix[1][1]` (top-right corner), looking for characters that are common to both strings. It adds those characters to a new string, `lcs`. +This backtracks from `matrix[n+1][m+1]` (bottom-right corner) to `matrix[1][1]` (top-left corner), looking for characters that are common to both strings. It adds those characters to a new string, `lcs`. The `charInSequence` variable is an index into the string given by `self`. Initially this points to the last character of the string. Each time we decrement `i`, we also move back `charInSequence`. When the two characters are found to be equal, we add the character at `self[charInSequence]` to the new `lcs` string. (We can't just write `self[i]` because `i` may not map to the current position inside the Swift string.) From 898db6fd3f266812be8387a2b2478d5f072cf872 Mon Sep 17 00:00:00 2001 From: Sergey Pugach Date: Mon, 30 Apr 2018 04:37:26 +0300 Subject: [PATCH 093/327] Refactors LinkedList implementation to be more Swifty. (#705) * fix versions merge * replace if to guard check --- .../LinkedList.playground/Contents.swift | 585 ++++++++-------- Linked List/LinkedList.swift | 263 ++++--- Linked List/Tests/LinkedListTests.swift | 662 +++++++++--------- 3 files changed, 779 insertions(+), 731 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 2ce3b4d66..4b58bb65e 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -9,371 +9,364 @@ print("Hello, Swift 4!") #endif public final class LinkedList { - - /// Linked List's Node Class Declaration - public class LinkedListNode { - var value: T - var next: LinkedListNode? - weak var previous: LinkedListNode? - - public init(value: T) { - self.value = value + + /// Linked List's Node Class Declaration + public class LinkedListNode { + var value: T + var next: LinkedListNode? + weak var previous: LinkedListNode? + + public init(value: T) { + self.value = value + } } - } - - /// Typealiasing the node class to increase readability of code - public typealias Node = LinkedListNode - - /// The head of the Linked List - fileprivate var head: Node? - - /// Default initializer - public init() {} - - /// Computed property to check if the linked list is empty - public var isEmpty: Bool { - return head == nil - } - - /// Computed property to get the first node in the linked list (if any) - public var first: Node? { - return head - } - - /// Computed property to iterate through the linked list and return the last node in the list (if any) - public var last: Node? { - guard var node = head else { - return nil + + /// Typealiasing the node class to increase readability of code + public typealias Node = LinkedListNode + + + /// The head of the Linked List + private(set) var head: Node? + + /// Computed property to iterate through the linked list and return the last node in the list (if any) + public var last: Node? { + guard var node = head else { + return nil + } + + while let next = node.next { + node = next + } + return node } - while let next = node.next { - node = next + /// Computed property to check if the linked list is empty + public var isEmpty: Bool { + return head == nil } - return node - } - - /// Computed property to iterate through the linked list and return the total number of nodes - public var count: Int { - guard var node = head else { - return 0 + + /// Computed property to iterate through the linked list and return the total number of nodes + public var count: Int { + guard var node = head else { + return 0 + } + + var count = 1 + while let next = node.next { + node = next + count += 1 + } + return count } - var count = 1 - while let next = node.next { - node = next - count += 1 + /// Default initializer + public init() {} + + + /// Subscript function to return the node at a specific index + /// + /// - Parameter index: Integer value of the requested value's index + public subscript(index: Int) -> T { + let node = self.node(at: index) + return node.value } - return count - } - - /// Function to return the node at a specific index. Crashes if index is out of bounds (0...self.count) - /// - /// - Parameter index: Integer value of the node's index to be returned - /// - Returns: Optional LinkedListNode - public func node(at index: Int) -> Node { - assert(head != nil, "List is empty") - assert(index >= 0, "index must be greater than 0") - if index == 0 { - return head! - } else { - var node = head!.next - for _ in 1.. Node { + assert(head != nil, "List is empty") + assert(index >= 0, "index must be greater than 0") + + if index == 0 { + return head! + } else { + var node = head!.next + for _ in 1.. T { - let node = self.node(at: index) - return node.value - } - - /// Append a value to the end of the list - /// - /// - Parameter value: The data value to be appended - public func append(_ value: T) { - let newNode = Node(value: value) - self.append(newNode) - } - - /// Append a copy of a LinkedListNode to the end of the list. - /// - /// - Parameter node: The node containing the value to be appended - public func append(_ node: Node) { - let newNode = node - if let lastNode = last { - newNode.previous = lastNode - lastNode.next = newNode - } else { - head = newNode + + /// Append a value to the end of the list + /// + /// - Parameter value: The data value to be appended + public func append(_ value: T) { + let newNode = Node(value: value) + append(newNode) + } + + /// Append a copy of a LinkedListNode to the end of the list. + /// + /// - Parameter node: The node containing the value to be appended + public func append(_ node: Node) { + let newNode = node + if let lastNode = last { + newNode.previous = lastNode + lastNode.next = newNode + } else { + head = newNode + } + } + + /// Append a copy of a LinkedList to the end of the list. + /// + /// - Parameter list: The list to be copied and appended. + public func append(_ list: LinkedList) { + var nodeToCopy = list.head + while let node = nodeToCopy { + append(node.value) + nodeToCopy = node.next + } + } + + /// Insert a value at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameters: + /// - value: The data value to be inserted + /// - index: Integer value of the index to be insterted at + public func insert(_ value: T, at index: Int) { + let newNode = Node(value: value) + insert(newNode, at: index) + } + + /// Insert a copy of a node at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameters: + /// - node: The node containing the value to be inserted + /// - index: Integer value of the index to be inserted at + public func insert(_ newNode: Node, at index: Int) { + if index == 0 { + newNode.next = head + head?.previous = newNode + head = newNode + } else { + let prev = node(at: index - 1) + let next = prev.next + newNode.previous = prev + newNode.next = next + next?.previous = newNode + prev.next = newNode + } } - } - - /// Append a copy of a LinkedList to the end of the list. - /// - /// - Parameter list: The list to be copied and appended. - public func append(_ list: LinkedList) { - var nodeToCopy = list.head - while let node = nodeToCopy { - self.append(node.value) - nodeToCopy = node.next + + /// Insert a copy of a LinkedList at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameters: + /// - list: The LinkedList to be copied and inserted + /// - index: Integer value of the index to be inserted at + public func insert(_ list: LinkedList, at index: Int) { + if list.isEmpty { return } + + if index == 0 { + list.last?.next = head + head = list.head + } else { + let prev = node(at: index - 1) + let next = prev.next + + prev.next = list.head + list.head?.previous = prev + + list.last?.next = next + next?.previous = list.last?.next + } } - } - - /// Insert a value at a specific index. Crashes if index is out of bounds (0...self.count) - /// - /// - Parameters: - /// - value: The data value to be inserted - /// - index: Integer value of the index to be insterted at - public func insert(_ value: T, at index: Int) { - let newNode = Node(value: value) - self.insert(newNode, at: index) - } - - /// Insert a copy of a node at a specific index. Crashes if index is out of bounds (0...self.count) - /// - /// - Parameters: - /// - node: The node containing the value to be inserted - /// - index: Integer value of the index to be inserted at - public func insert(_ newNode: Node, at index: Int) { - if index == 0 { - newNode.next = head - head?.previous = newNode - head = newNode - } else { - let prev = node(at: index-1) - let next = prev.next - newNode.previous = prev - newNode.next = next - next?.previous = newNode - prev.next = newNode + + /// Function to remove all nodes/value from the list + public func removeAll() { + head = nil } - } - /// Insert a copy of a LinkedList at a specific index. Crashes if index is out of bounds (0...self.count) - /// - /// - Parameters: - /// - list: The LinkedList to be copied and inserted - /// - index: Integer value of the index to be inserted at - public func insert(_ list: LinkedList, at index: Int) { - if list.isEmpty { return } + /// Function to remove a specific node. + /// + /// - Parameter node: The node to be deleted + /// - Returns: The data value contained in the deleted node. + @discardableResult public func remove(node: Node) -> T { + let prev = node.previous + let next = node.next + + if let prev = prev { + prev.next = next + } else { + head = next + } + next?.previous = prev + + node.previous = nil + node.next = nil + return node.value + } - if index == 0 { - list.last?.next = head - head = list.head - } else { - let prev = node(at: index-1) - let next = prev.next - - prev.next = list.head - list.head?.previous = prev - - list.last?.next = next - next?.previous = list.last?.next + /// Function to remove the last node/value in the list. Crashes if the list is empty + /// + /// - Returns: The data value contained in the deleted node. + @discardableResult public func removeLast() -> T { + assert(!isEmpty) + return remove(node: last!) } - } - - /// Function to remove all nodes/value from the list - public func removeAll() { - head = nil - } - - /// Function to remove a specific node. - /// - /// - Parameter node: The node to be deleted - /// - Returns: The data value contained in the deleted node. - @discardableResult public func remove(node: Node) -> T { - let prev = node.previous - let next = node.next - - if let prev = prev { - prev.next = next - } else { - head = next + + /// Function to remove a node/value at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameter index: Integer value of the index of the node to be removed + /// - Returns: The data value contained in the deleted node + @discardableResult public func remove(at index: Int) -> T { + let node = self.node(at: index) + return remove(node: node) } - next?.previous = prev - - node.previous = nil - node.next = nil - return node.value - } - - /// Function to remove the last node/value in the list. Crashes if the list is empty - /// - /// - Returns: The data value contained in the deleted node. - @discardableResult public func removeLast() -> T { - assert(!isEmpty) - return remove(node: last!) - } - - /// Function to remove a node/value at a specific index. Crashes if index is out of bounds (0...self.count) - /// - /// - Parameter index: Integer value of the index of the node to be removed - /// - Returns: The data value contained in the deleted node - @discardableResult public func remove(at index: Int) -> T { - let node = self.node(at: index) - return remove(node: node) - } } //: End of the base class declarations & beginning of extensions' declarations: // MARK: - Extension to enable the standard conversion of a list to String extension LinkedList: CustomStringConvertible { - public var description: String { - var s = "[" - var node = head - while node != nil { - s += "\(node!.value)" - node = node!.next - if node != nil { s += ", " } + public var description: String { + var s = "[" + var node = head + while let nd = node { + s += "\(nd.value)" + node = nd.next + if node != nil { s += ", " } + } + return s + "]" } - return s + "]" - } } // MARK: - Extension to add a 'reverse' function to the list extension LinkedList { - public func reverse() { - var node = head - while let currentNode = node { - node = currentNode.next - swap(¤tNode.next, ¤tNode.previous) - head = currentNode + public func reverse() { + var node = head + while let currentNode = node { + node = currentNode.next + swap(¤tNode.next, ¤tNode.previous) + head = currentNode + } } - } } // MARK: - An extension with an implementation of 'map' & 'filter' functions extension LinkedList { - public func map(transform: (T) -> U) -> LinkedList { - let result = LinkedList() - var node = head - while node != nil { - result.append(transform(node!.value)) - node = node!.next + public func map(transform: (T) -> U) -> LinkedList { + let result = LinkedList() + var node = head + while let nd = node { + result.append(transform(nd.value)) + node = nd.next + } + return result } - return result - } - - public func filter(predicate: (T) -> Bool) -> LinkedList { - let result = LinkedList() - var node = head - while node != nil { - if predicate(node!.value) { - result.append(node!.value) - } - node = node!.next + + public func filter(predicate: (T) -> Bool) -> LinkedList { + let result = LinkedList() + var node = head + while let nd = node { + if predicate(nd.value) { + result.append(nd.value) + } + node = nd.next + } + return result } - return result - } } // MARK: - Extension to enable initialization from an Array extension LinkedList { - convenience init(array: Array) { - self.init() - - for element in array { - self.append(element) + convenience init(array: Array) { + self.init() + + array.forEach { append($0) } } - } } // MARK: - Extension to enable initialization from an Array Literal extension LinkedList: ExpressibleByArrayLiteral { - public convenience init(arrayLiteral elements: T...) { - self.init() - - for element in elements { - self.append(element) + public convenience init(arrayLiteral elements: T...) { + self.init() + + elements.forEach { append($0) } } - } } // MARK: - Collection -extension LinkedList : Collection { - - public typealias Index = LinkedListIndex - - /// The position of the first element in a nonempty collection. - /// - /// If the collection is empty, `startIndex` is equal to `endIndex`. - /// - Complexity: O(1) - public var startIndex: Index { - get { - return LinkedListIndex(node: head, tag: 0) +extension LinkedList: Collection { + + public typealias Index = LinkedListIndex + + /// The position of the first element in a nonempty collection. + /// + /// If the collection is empty, `startIndex` is equal to `endIndex`. + /// - Complexity: O(1) + public var startIndex: Index { + get { + return LinkedListIndex(node: head, tag: 0) + } + } + + /// The collection's "past the end" position---that is, the position one + /// greater than the last valid subscript argument. + /// - Complexity: O(n), where n is the number of elements in the list. This can be improved by keeping a reference + /// to the last node in the collection. + public var endIndex: Index { + get { + if let h = self.head { + return LinkedListIndex(node: h, tag: count) + } else { + return LinkedListIndex(node: nil, tag: startIndex.tag) + } + } } - } - - /// The collection's "past the end" position---that is, the position one - /// greater than the last valid subscript argument. - /// - Complexity: O(n), where n is the number of elements in the list. This can be improved by keeping a reference - /// to the last node in the collection. - public var endIndex: Index { - get { - if let h = self.head { - return LinkedListIndex(node: h, tag: count) - } else { - return LinkedListIndex(node: nil, tag: startIndex.tag) - } + + public subscript(position: Index) -> T { + get { + return position.node!.value + } } - } - - public subscript(position: Index) -> T { - get { - return position.node!.value + + public func index(after idx: Index) -> Index { + return LinkedListIndex(node: idx.node?.next, tag: idx.tag + 1) } - } - - public func index(after idx: Index) -> Index { - return LinkedListIndex(node: idx.node?.next, tag: idx.tag+1) - } } // MARK: - Collection Index /// Custom index type that contains a reference to the node at index 'tag' -public struct LinkedListIndex : Comparable { - fileprivate let node: LinkedList.LinkedListNode? - fileprivate let tag: Int - - public static func==(lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { - return (lhs.tag == rhs.tag) - } - - public static func< (lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { - return (lhs.tag < rhs.tag) - } +public struct LinkedListIndex: Comparable { + fileprivate let node: LinkedList.LinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } } //: Ok, now that the declarations are done, let's see our Linked List in action: let list = LinkedList() list.isEmpty // true -list.first // nil +list.head // nil list.last // nil list.append("Hello") list.isEmpty // false -list.first!.value // "Hello" +list.head!.value // "Hello" list.last!.value // "Hello" list.count // 1 list.append("World") -list.first!.value // "Hello" +list.head!.value // "Hello" list.last!.value // "World" list.count // 2 -list.first!.previous // nil -list.first!.next!.value // "World" +list.head!.previous // nil +list.head!.next!.value // "World" list.last!.previous!.value // "Hello" list.last!.next // nil @@ -409,7 +402,7 @@ m // [8, 6, 5] let f = list.filter { s in s.count > 5 } f // [Universe, Swifty] -list.remove(node: list.first!) // "Universe" +list.remove(node: list.head!) // "Universe" list.count // 2 list[0] // "Swifty" list[1] // "Hello" @@ -464,7 +457,7 @@ let value = collection[index2] // 3 // Iterating in a for loop, since the Sequence protocol allows this. var sum = 0 for element in collection { - sum += element + sum += element } // sum is 15 diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 569cea82b..285c85588 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -1,29 +1,24 @@ public final class LinkedList { - + + /// Linked List's Node Class Declaration public class LinkedListNode { var value: T var next: LinkedListNode? weak var previous: LinkedListNode? - + public init(value: T) { self.value = value } } - + + /// Typealiasing the node class to increase readability of code public typealias Node = LinkedListNode - - fileprivate var head: Node? - - public init() {} - - public var isEmpty: Bool { - return head == nil - } - - public var first: Node? { - return head - } - + + + /// The head of the Linked List + private(set) var head: Node? + + /// Computed property to iterate through the linked list and return the last node in the list (if any) public var last: Node? { guard var node = head else { return nil @@ -34,7 +29,13 @@ public final class LinkedList { } return node } - + + /// Computed property to check if the linked list is empty + public var isEmpty: Bool { + return head == nil + } + + /// Computed property to iterate through the linked list and return the total number of nodes public var count: Int { guard var node = head else { return 0 @@ -48,9 +49,26 @@ public final class LinkedList { return count } + /// Default initializer + public init() {} + + + /// Subscript function to return the node at a specific index + /// + /// - Parameter index: Integer value of the requested value's index + public subscript(index: Int) -> T { + let node = self.node(at: index) + return node.value + } + + /// Function to return the node at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameter index: Integer value of the node's index to be returned + /// - Returns: LinkedListNode public func node(at index: Int) -> Node { assert(head != nil, "List is empty") assert(index >= 0, "index must be greater than 0") + if index == 0 { return head! } else { @@ -66,17 +84,18 @@ public final class LinkedList { return node! } } - - public subscript(index: Int) -> T { - let node = self.node(at: index) - return node.value - } - + + /// Append a value to the end of the list + /// + /// - Parameter value: The data value to be appended public func append(_ value: T) { let newNode = Node(value: value) - self.append(newNode) + append(newNode) } - + + /// Append a copy of a LinkedListNode to the end of the list. + /// + /// - Parameter node: The node containing the value to be appended public func append(_ node: Node) { let newNode = node if let lastNode = last { @@ -86,27 +105,40 @@ public final class LinkedList { head = newNode } } - + + /// Append a copy of a LinkedList to the end of the list. + /// + /// - Parameter list: The list to be copied and appended. public func append(_ list: LinkedList) { var nodeToCopy = list.head while let node = nodeToCopy { - self.append(node.value) + append(node.value) nodeToCopy = node.next } } - + + /// Insert a value at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameters: + /// - value: The data value to be inserted + /// - index: Integer value of the index to be insterted at public func insert(_ value: T, at index: Int) { let newNode = Node(value: value) - self.insert(newNode, at: index) + insert(newNode, at: index) } - + + /// Insert a copy of a node at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameters: + /// - node: The node containing the value to be inserted + /// - index: Integer value of the index to be inserted at public func insert(_ newNode: Node, at index: Int) { if index == 0 { newNode.next = head head?.previous = newNode head = newNode } else { - let prev = node(at: index-1) + let prev = node(at: index - 1) let next = prev.next newNode.previous = prev newNode.next = next @@ -115,14 +147,19 @@ public final class LinkedList { } } + /// Insert a copy of a LinkedList at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameters: + /// - list: The LinkedList to be copied and inserted + /// - index: Integer value of the index to be inserted at public func insert(_ list: LinkedList, at index: Int) { - if list.isEmpty { return } + guard !list.isEmpty else { return } if index == 0 { list.last?.next = head head = list.head } else { - let prev = self.node(at: index-1) + let prev = node(at: index - 1) let next = prev.next prev.next = list.head @@ -133,50 +170,66 @@ public final class LinkedList { } } + /// Function to remove all nodes/value from the list public func removeAll() { head = nil } - + + /// Function to remove a specific node. + /// + /// - Parameter node: The node to be deleted + /// - Returns: The data value contained in the deleted node. @discardableResult public func remove(node: Node) -> T { let prev = node.previous let next = node.next - + if let prev = prev { prev.next = next } else { head = next } next?.previous = prev - + node.previous = nil node.next = nil return node.value } - + + /// Function to remove the last node/value in the list. Crashes if the list is empty + /// + /// - Returns: The data value contained in the deleted node. @discardableResult public func removeLast() -> T { assert(!isEmpty) return remove(node: last!) } - + + /// Function to remove a node/value at a specific index. Crashes if index is out of bounds (0...self.count) + /// + /// - Parameter index: Integer value of the index of the node to be removed + /// - Returns: The data value contained in the deleted node @discardableResult public func remove(at index: Int) -> T { let node = self.node(at: index) return remove(node: node) } } +//: End of the base class declarations & beginning of extensions' declarations: + +// MARK: - Extension to enable the standard conversion of a list to String extension LinkedList: CustomStringConvertible { public var description: String { var s = "[" var node = head - while node != nil { - s += "\(node!.value)" - node = node!.next + while let nd = node { + s += "\(nd.value)" + node = nd.next if node != nil { s += ", " } } return s + "]" } } +// MARK: - Extension to add a 'reverse' function to the list extension LinkedList { public func reverse() { var node = head @@ -188,99 +241,101 @@ extension LinkedList { } } +// MARK: - An extension with an implementation of 'map' & 'filter' functions extension LinkedList { public func map(transform: (T) -> U) -> LinkedList { let result = LinkedList() var node = head - while node != nil { - result.append(transform(node!.value)) - node = node!.next + while let nd = node { + result.append(transform(nd.value)) + node = nd.next } return result } - + public func filter(predicate: (T) -> Bool) -> LinkedList { let result = LinkedList() var node = head - while node != nil { - if predicate(node!.value) { - result.append(node!.value) + while let nd = node { + if predicate(nd.value) { + result.append(nd.value) } - node = node!.next + node = nd.next } return result } } +// MARK: - Extension to enable initialization from an Array extension LinkedList { convenience init(array: Array) { self.init() - - for element in array { - self.append(element) - } + + array.forEach { append($0) } } } +// MARK: - Extension to enable initialization from an Array Literal extension LinkedList: ExpressibleByArrayLiteral { - public convenience init(arrayLiteral elements: T...) { - self.init() - - for element in elements { - self.append(element) + public convenience init(arrayLiteral elements: T...) { + self.init() + + elements.forEach { append($0) } } - } } -extension LinkedList : Collection { - - public typealias Index = LinkedListIndex - - /// The position of the first element in a nonempty collection. - /// - /// If the collection is empty, `startIndex` is equal to `endIndex`. - /// - Complexity: O(1) - public var startIndex: Index { - get { - return LinkedListIndex(node: head, tag: 0) +// MARK: - Collection +extension LinkedList: Collection { + + public typealias Index = LinkedListIndex + + /// The position of the first element in a nonempty collection. + /// + /// If the collection is empty, `startIndex` is equal to `endIndex`. + /// - Complexity: O(1) + public var startIndex: Index { + get { + return LinkedListIndex(node: head, tag: 0) + } + } + + /// The collection's "past the end" position---that is, the position one + /// greater than the last valid subscript argument. + /// - Complexity: O(n), where n is the number of elements in the list. This can be improved by keeping a reference + /// to the last node in the collection. + public var endIndex: Index { + get { + if let h = self.head { + return LinkedListIndex(node: h, tag: count) + } else { + return LinkedListIndex(node: nil, tag: startIndex.tag) + } + } } - } - - /// The collection's "past the end" position---that is, the position one - /// greater than the last valid subscript argument. - /// - Complexity: O(n), where n is the number of elements in the list. This can be improved by keeping a reference - /// to the last node in the collection. - public var endIndex: Index { - get { - if let h = self.head { - return LinkedListIndex(node: h, tag: count) - } else { - return LinkedListIndex(node: nil, tag: startIndex.tag) - } + + public subscript(position: Index) -> T { + get { + return position.node!.value + } } - } - - public subscript(position: Index) -> T { - get { - return position.node!.value + + public func index(after idx: Index) -> Index { + return LinkedListIndex(node: idx.node?.next, tag: idx.tag + 1) } - } - - public func index(after idx: Index) -> Index { - return LinkedListIndex(node: idx.node?.next, tag: idx.tag+1) - } } +// MARK: - Collection Index /// Custom index type that contains a reference to the node at index 'tag' -public struct LinkedListIndex : Comparable { - fileprivate let node: LinkedList.LinkedListNode? - fileprivate let tag: Int - - public static func==(lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { - return (lhs.tag == rhs.tag) - } - - public static func< (lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { - return (lhs.tag < rhs.tag) - } +public struct LinkedListIndex: Comparable { + fileprivate let node: LinkedList.LinkedListNode? + fileprivate let tag: Int + + public static func==(lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag == rhs.tag) + } + + public static func< (lhs: LinkedListIndex, rhs: LinkedListIndex) -> Bool { + return (lhs.tag < rhs.tag) + } } + diff --git a/Linked List/Tests/LinkedListTests.swift b/Linked List/Tests/LinkedListTests.swift index 9ed698849..b16af05ba 100755 --- a/Linked List/Tests/LinkedListTests.swift +++ b/Linked List/Tests/LinkedListTests.swift @@ -1,339 +1,339 @@ import XCTest class LinkedListTest: XCTestCase { - let numbers = [8, 2, 10, 9, 7, 5] - - fileprivate func buildList() -> LinkedList { - let list = LinkedList() - for number in numbers { - list.append(number) + let numbers = [8, 2, 10, 9, 7, 5] + + fileprivate func buildList() -> LinkedList { + let list = LinkedList() + for number in numbers { + list.append(number) + } + return list } - return list - } - - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } - - func testEmptyList() { - let list = LinkedList() - XCTAssertTrue(list.isEmpty) - XCTAssertEqual(list.count, 0) - XCTAssertNil(list.first) - XCTAssertNil(list.last) - } - - func testListWithOneElement() { - let list = LinkedList() - list.append(123) - - XCTAssertFalse(list.isEmpty) - XCTAssertEqual(list.count, 1) - - XCTAssertNotNil(list.first) - XCTAssertNil(list.first!.previous) - XCTAssertNil(list.first!.next) - XCTAssertEqual(list.first!.value, 123) - - XCTAssertNotNil(list.last) - XCTAssertNil(list.last!.previous) - XCTAssertNil(list.last!.next) - XCTAssertEqual(list.last!.value, 123) - - XCTAssertTrue(list.first === list.last) - } - - func testListWithTwoElements() { - let list = LinkedList() - list.append(123) - list.append(456) - - XCTAssertEqual(list.count, 2) - - XCTAssertNotNil(list.first) - XCTAssertEqual(list.first!.value, 123) - - XCTAssertNotNil(list.last) - XCTAssertEqual(list.last!.value, 456) - - XCTAssertTrue(list.first !== list.last) - - XCTAssertNil(list.first!.previous) - XCTAssertTrue(list.first!.next === list.last) - XCTAssertTrue(list.last!.previous === list.first) - XCTAssertNil(list.last!.next) - } - - func testListWithThreeElements() { - let list = LinkedList() - list.append(123) - list.append(456) - list.append(789) - - XCTAssertEqual(list.count, 3) - - XCTAssertNotNil(list.first) - XCTAssertEqual(list.first!.value, 123) - - let second = list.first!.next - XCTAssertNotNil(second) - XCTAssertEqual(second!.value, 456) - - XCTAssertNotNil(list.last) - XCTAssertEqual(list.last!.value, 789) - - XCTAssertNil(list.first!.previous) - XCTAssertTrue(list.first!.next === second) - XCTAssertTrue(second!.previous === list.first) - XCTAssertTrue(second!.next === list.last) - XCTAssertTrue(list.last!.previous === second) - XCTAssertNil(list.last!.next) - } - - func testNodeAtIndexInListWithOneElement() { - let list = LinkedList() - list.append(123) - - let node = list.node(at: 0) - XCTAssertNotNil(node) - XCTAssertEqual(node.value, 123) - XCTAssertTrue(node === list.first) - } - - func testNodeAtIndex() { - let list = buildList() - - let nodeCount = list.count - XCTAssertEqual(nodeCount, numbers.count) - - let first = list.node(at: 0) - XCTAssertNotNil(first) - XCTAssertTrue(first === list.first) - XCTAssertEqual(first.value, numbers[0]) - - let last = list.node(at: nodeCount - 1) - XCTAssertNotNil(last) - XCTAssertTrue(last === list.last) - XCTAssertEqual(last.value, numbers[nodeCount - 1]) - - for i in 0..=4.0) + print("Hello, Swift 4!") + #endif } - } - - func testSubscript() { - let list = buildList() - for i in 0 ..< list.count { - XCTAssertEqual(list[i], numbers[i]) + + func testEmptyList() { + let list = LinkedList() + XCTAssertTrue(list.isEmpty) + XCTAssertEqual(list.count, 0) + XCTAssertNil(list.first) + XCTAssertNil(list.last) + } + + func testListWithOneElement() { + let list = LinkedList() + list.append(123) + + XCTAssertFalse(list.isEmpty) + XCTAssertEqual(list.count, 1) + + XCTAssertNotNil(list.first) + XCTAssertNil(list.head!.previous) + XCTAssertNil(list.head!.next) + XCTAssertEqual(list.head!.value, 123) + + XCTAssertNotNil(list.last) + XCTAssertNil(list.last!.previous) + XCTAssertNil(list.last!.next) + XCTAssertEqual(list.last!.value, 123) + + XCTAssertTrue(list.head === list.last) + } + + func testListWithTwoElements() { + let list = LinkedList() + list.append(123) + list.append(456) + + XCTAssertEqual(list.count, 2) + + XCTAssertNotNil(list.first) + XCTAssertEqual(list.head!.value, 123) + + XCTAssertNotNil(list.last) + XCTAssertEqual(list.last!.value, 456) + + XCTAssertTrue(list.head !== list.last) + + XCTAssertNil(list.head!.previous) + XCTAssertTrue(list.head!.next === list.last) + XCTAssertTrue(list.last!.previous === list.head) + XCTAssertNil(list.last!.next) + } + + func testListWithThreeElements() { + let list = LinkedList() + list.append(123) + list.append(456) + list.append(789) + + XCTAssertEqual(list.count, 3) + + XCTAssertNotNil(list.first) + XCTAssertEqual(list.head!.value, 123) + + let second = list.head!.next + XCTAssertNotNil(second) + XCTAssertEqual(second!.value, 456) + + XCTAssertNotNil(list.last) + XCTAssertEqual(list.last!.value, 789) + + XCTAssertNil(list.head!.previous) + XCTAssertTrue(list.head!.next === second) + XCTAssertTrue(second!.previous === list.head) + XCTAssertTrue(second!.next === list.last) + XCTAssertTrue(list.last!.previous === second) + XCTAssertNil(list.last!.next) + } + + func testNodeAtIndexInListWithOneElement() { + let list = LinkedList() + list.append(123) + + let node = list.node(at: 0) + XCTAssertNotNil(node) + XCTAssertEqual(node.value, 123) + XCTAssertTrue(node === list.head) + } + + func testNodeAtIndex() { + let list = buildList() + + let nodeCount = list.count + XCTAssertEqual(nodeCount, numbers.count) + + let first = list.node(at: 0) + XCTAssertNotNil(first) + XCTAssertTrue(first === list.head) + XCTAssertEqual(first.value, numbers[0]) + + let last = list.node(at: nodeCount - 1) + XCTAssertNotNil(last) + XCTAssertTrue(last === list.last) + XCTAssertEqual(last.value, numbers[nodeCount - 1]) + + for i in 0..() + list.insert(123, at: 0) + + XCTAssertFalse(list.isEmpty) + XCTAssertEqual(list.count, 1) + + let node = list.node(at: 0) + XCTAssertNotNil(node) + XCTAssertEqual(node.value, 123) + } + + func testInsertAtIndex() { + let list = buildList() + let prev = list.node(at: 2) + let next = list.node(at: 3) + let nodeCount = list.count + + list.insert(444, at: 3) + + let node = list.node(at: 3) + XCTAssertNotNil(node) + XCTAssertEqual(node.value, 444) + XCTAssertEqual(nodeCount + 1, list.count) + + XCTAssertFalse(prev === node) + XCTAssertFalse(next === node) + XCTAssertTrue(prev.next === node) + XCTAssertTrue(next.previous === node) } - } - - func testInsertAtIndexInEmptyList() { - let list = LinkedList() - list.insert(123, at: 0) - - XCTAssertFalse(list.isEmpty) - XCTAssertEqual(list.count, 1) - - let node = list.node(at: 0) - XCTAssertNotNil(node) - XCTAssertEqual(node.value, 123) - } - - func testInsertAtIndex() { - let list = buildList() - let prev = list.node(at: 2) - let next = list.node(at: 3) - let nodeCount = list.count - - list.insert(444, at: 3) - - let node = list.node(at: 3) - XCTAssertNotNil(node) - XCTAssertEqual(node.value, 444) - XCTAssertEqual(nodeCount + 1, list.count) - - XCTAssertFalse(prev === node) - XCTAssertFalse(next === node) - XCTAssertTrue(prev.next === node) - XCTAssertTrue(next.previous === node) - } - - func testInsertListAtIndex() { - let list = buildList() - let list2 = LinkedList() - list2.append(99) - list2.append(102) - list.insert(list2, at: 2) - XCTAssertTrue(list.count == 8) - XCTAssertEqual(list.node(at: 1).value, 2) - XCTAssertEqual(list.node(at: 2).value, 99) - XCTAssertEqual(list.node(at: 3).value, 102) - XCTAssertEqual(list.node(at: 4).value, 10) - } - - func testInsertListAtFirstIndex() { - let list = buildList() - let list2 = LinkedList() - list2.append(99) - list2.append(102) - list.insert(list2, at: 0) - XCTAssertTrue(list.count == 8) - XCTAssertEqual(list.node(at: 0).value, 99) - XCTAssertEqual(list.node(at: 1).value, 102) - XCTAssertEqual(list.node(at: 2).value, 8) - } - - func testInsertListAtLastIndex() { - let list = buildList() - let list2 = LinkedList() - list2.append(99) - list2.append(102) - list.insert(list2, at: list.count) - XCTAssertTrue(list.count == 8) - XCTAssertEqual(list.node(at: 5).value, 5) - XCTAssertEqual(list.node(at: 6).value, 99) - XCTAssertEqual(list.node(at: 7).value, 102) - } - - func testAppendList() { - let list = buildList() - let list2 = LinkedList() - list2.append(99) - list2.append(102) - list.append(list2) - XCTAssertTrue(list.count == 8) - XCTAssertEqual(list.node(at: 5).value, 5) - XCTAssertEqual(list.node(at: 6).value, 99) - XCTAssertEqual(list.node(at: 7).value, 102) - } - - func testAppendListToEmptyList() { - let list = LinkedList() - let list2 = LinkedList() - list2.append(5) - list2.append(10) - list.append(list2) - XCTAssertTrue(list.count == 2) - XCTAssertEqual(list.node(at: 0).value, 5) - XCTAssertEqual(list.node(at: 1).value, 10) - } - - func testRemoveAtIndexOnListWithOneElement() { - let list = LinkedList() - list.append(123) - - let value = list.remove(at: 0) - XCTAssertEqual(value, 123) - - XCTAssertTrue(list.isEmpty) - XCTAssertEqual(list.count, 0) - XCTAssertNil(list.first) - XCTAssertNil(list.last) - } - - func testRemoveAtIndex() { - let list = buildList() - let prev = list.node(at: 2) - let next = list.node(at: 3) - let nodeCount = list.count - - list.insert(444, at: 3) - - let value = list.remove(at: 3) - XCTAssertEqual(value, 444) - - let node = list.node(at: 3) - XCTAssertTrue(next === node) - XCTAssertTrue(prev.next === node) - XCTAssertTrue(node.previous === prev) - XCTAssertEqual(nodeCount, list.count) - } - - func testRemoveLastOnListWithOneElement() { - let list = LinkedList() - list.append(123) - - let value = list.removeLast() - XCTAssertEqual(value, 123) - - XCTAssertTrue(list.isEmpty) - XCTAssertEqual(list.count, 0) - XCTAssertNil(list.first) - XCTAssertNil(list.last) - } - - func testRemoveLast() { - let list = buildList() - let last = list.last - let prev = last!.previous - let nodeCount = list.count - - let value = list.removeLast() - XCTAssertEqual(value, 5) - - XCTAssertNil(last!.previous) - XCTAssertNil(last!.next) - - XCTAssertNil(prev!.next) - XCTAssertTrue(list.last === prev) - XCTAssertEqual(nodeCount - 1, list.count) - } - - func testRemoveAll() { - let list = buildList() - list.removeAll() - XCTAssertTrue(list.isEmpty) - XCTAssertEqual(list.count, 0) - XCTAssertNil(list.first) - XCTAssertNil(list.last) - } - - func testReverseLinkedList() { - let list = buildList() - let first = list.first - let last = list.last - let nodeCount = list.count - - list.reverse() - - XCTAssertTrue(first === list.last) - XCTAssertTrue(last === list.first) - XCTAssertEqual(nodeCount, list.count) - } - - func testArrayLiteralInitTypeInfer() { - let arrayLiteralInitInfer: LinkedList = [1.0, 2.0, 3.0] - - XCTAssertEqual(arrayLiteralInitInfer.count, 3) - XCTAssertEqual(arrayLiteralInitInfer.first?.value, 1.0) - XCTAssertEqual(arrayLiteralInitInfer.last?.value, 3.0) - XCTAssertEqual(arrayLiteralInitInfer[1], 2.0) - XCTAssertEqual(arrayLiteralInitInfer.removeLast(), 3.0) - XCTAssertEqual(arrayLiteralInitInfer.count, 2) - } - - func testArrayLiteralInitExplicit() { - let arrayLiteralInitExplicit: LinkedList = [1, 2, 3] - - XCTAssertEqual(arrayLiteralInitExplicit.count, 3) - XCTAssertEqual(arrayLiteralInitExplicit.first?.value, 1) - XCTAssertEqual(arrayLiteralInitExplicit.last?.value, 3) - XCTAssertEqual(arrayLiteralInitExplicit[1], 2) - XCTAssertEqual(arrayLiteralInitExplicit.removeLast(), 3) - XCTAssertEqual(arrayLiteralInitExplicit.count, 2) - } - - func testConformanceToCollectionProtocol() { - let collection: LinkedList = [1, 2, 3, 4, 5] - let index2 = collection.index(collection.startIndex, offsetBy: 2) - let value = collection[index2] - XCTAssertTrue(value == 3) - } + func testInsertListAtIndex() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + list2.append(102) + list.insert(list2, at: 2) + XCTAssertTrue(list.count == 8) + XCTAssertEqual(list.node(at: 1).value, 2) + XCTAssertEqual(list.node(at: 2).value, 99) + XCTAssertEqual(list.node(at: 3).value, 102) + XCTAssertEqual(list.node(at: 4).value, 10) + } + + func testInsertListAtFirstIndex() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + list2.append(102) + list.insert(list2, at: 0) + XCTAssertTrue(list.count == 8) + XCTAssertEqual(list.node(at: 0).value, 99) + XCTAssertEqual(list.node(at: 1).value, 102) + XCTAssertEqual(list.node(at: 2).value, 8) + } + + func testInsertListAtLastIndex() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + list2.append(102) + list.insert(list2, at: list.count) + XCTAssertTrue(list.count == 8) + XCTAssertEqual(list.node(at: 5).value, 5) + XCTAssertEqual(list.node(at: 6).value, 99) + XCTAssertEqual(list.node(at: 7).value, 102) + } + + func testAppendList() { + let list = buildList() + let list2 = LinkedList() + list2.append(99) + list2.append(102) + list.append(list2) + XCTAssertTrue(list.count == 8) + XCTAssertEqual(list.node(at: 5).value, 5) + XCTAssertEqual(list.node(at: 6).value, 99) + XCTAssertEqual(list.node(at: 7).value, 102) + } + + func testAppendListToEmptyList() { + let list = LinkedList() + let list2 = LinkedList() + list2.append(5) + list2.append(10) + list.append(list2) + XCTAssertTrue(list.count == 2) + XCTAssertEqual(list.node(at: 0).value, 5) + XCTAssertEqual(list.node(at: 1).value, 10) + } + + func testRemoveAtIndexOnListWithOneElement() { + let list = LinkedList() + list.append(123) + + let value = list.remove(at: 0) + XCTAssertEqual(value, 123) + + XCTAssertTrue(list.isEmpty) + XCTAssertEqual(list.count, 0) + XCTAssertNil(list.first) + XCTAssertNil(list.last) + } + + func testRemoveAtIndex() { + let list = buildList() + let prev = list.node(at: 2) + let next = list.node(at: 3) + let nodeCount = list.count + + list.insert(444, at: 3) + + let value = list.remove(at: 3) + XCTAssertEqual(value, 444) + + let node = list.node(at: 3) + XCTAssertTrue(next === node) + XCTAssertTrue(prev.next === node) + XCTAssertTrue(node.previous === prev) + XCTAssertEqual(nodeCount, list.count) + } + + func testRemoveLastOnListWithOneElement() { + let list = LinkedList() + list.append(123) + + let value = list.removeLast() + XCTAssertEqual(value, 123) + + XCTAssertTrue(list.isEmpty) + XCTAssertEqual(list.count, 0) + XCTAssertNil(list.first) + XCTAssertNil(list.last) + } + + func testRemoveLast() { + let list = buildList() + let last = list.last + let prev = last!.previous + let nodeCount = list.count + + let value = list.removeLast() + XCTAssertEqual(value, 5) + + XCTAssertNil(last!.previous) + XCTAssertNil(last!.next) + + XCTAssertNil(prev!.next) + XCTAssertTrue(list.last === prev) + XCTAssertEqual(nodeCount - 1, list.count) + } + + func testRemoveAll() { + let list = buildList() + list.removeAll() + XCTAssertTrue(list.isEmpty) + XCTAssertEqual(list.count, 0) + XCTAssertNil(list.first) + XCTAssertNil(list.last) + } + + func testReverseLinkedList() { + let list = buildList() + let first = list.head + let last = list.last + let nodeCount = list.count + + list.reverse() + + XCTAssertTrue(first === list.last) + XCTAssertTrue(last === list.head) + XCTAssertEqual(nodeCount, list.count) + } + + func testArrayLiteralInitTypeInfer() { + let arrayLiteralInitInfer: LinkedList = [1.0, 2.0, 3.0] + + XCTAssertEqual(arrayLiteralInitInfer.count, 3) + XCTAssertEqual(arrayLiteralInitInfer.head?.value, 1.0) + XCTAssertEqual(arrayLiteralInitInfer.last?.value, 3.0) + XCTAssertEqual(arrayLiteralInitInfer[1], 2.0) + XCTAssertEqual(arrayLiteralInitInfer.removeLast(), 3.0) + XCTAssertEqual(arrayLiteralInitInfer.count, 2) + } + + func testArrayLiteralInitExplicit() { + let arrayLiteralInitExplicit: LinkedList = [1, 2, 3] + + XCTAssertEqual(arrayLiteralInitExplicit.count, 3) + XCTAssertEqual(arrayLiteralInitExplicit.head?.value, 1) + XCTAssertEqual(arrayLiteralInitExplicit.last?.value, 3) + XCTAssertEqual(arrayLiteralInitExplicit[1], 2) + XCTAssertEqual(arrayLiteralInitExplicit.removeLast(), 3) + XCTAssertEqual(arrayLiteralInitExplicit.count, 2) + } + + func testConformanceToCollectionProtocol() { + let collection: LinkedList = [1, 2, 3, 4, 5] + let index2 = collection.index(collection.startIndex, offsetBy: 2) + let value = collection[index2] + + XCTAssertTrue(value == 3) + } } From 444b993d571d955b36aa0aa64cd03dd1a31761b3 Mon Sep 17 00:00:00 2001 From: Bill Barbour Date: Tue, 8 May 2018 15:24:10 -0400 Subject: [PATCH 094/327] Updated number to be prime; and Swift 4 update --- Rabin-Karp/Rabin-Karp.playground/Contents.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Rabin-Karp/Rabin-Karp.playground/Contents.swift b/Rabin-Karp/Rabin-Karp.playground/Contents.swift index 739b74e2a..40cd176a6 100644 --- a/Rabin-Karp/Rabin-Karp.playground/Contents.swift +++ b/Rabin-Karp/Rabin-Karp.playground/Contents.swift @@ -8,7 +8,7 @@ print("Hello, Swift 4!") import UIKit struct Constants { - static let hashMultiplier = 69069 + static let hashMultiplier = 69061 } precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence } @@ -30,8 +30,8 @@ extension Character { // Find first position of pattern in the text using Rabin Karp algorithm public func search(text: String, pattern: String) -> Int { // convert to array of ints - let patternArray = pattern.flatMap { $0.asInt } - let textArray = text.flatMap { $0.asInt } + let patternArray = pattern.compactMap { $0.asInt } + let textArray = text.compactMap { $0.asInt } if textArray.count < patternArray.count { return -1 From 65e3d4d18485598b030068be0ab4b82c1c21b823 Mon Sep 17 00:00:00 2001 From: Ruslan Skorb Date: Mon, 30 Apr 2018 10:11:12 +0300 Subject: [PATCH 095/327] [Binary Search Tree] [enum] Fix `height`. https://en.wikipedia.org/wiki/Tree_\(data_structure\)\#Terminology --- Binary Search Tree/README.markdown | 4 ++-- Binary Search Tree/Solution 2/BinarySearchTree.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index 30dc8d922..0b382f204 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -615,8 +615,8 @@ This implementation is recursive, and each case of the enum will be treated diff public var height: Int { switch self { - case .Empty: return 0 - case .Leaf: return 1 + case .Empty: return -1 + case .Leaf: return 0 case let .Node(left, _, right): return 1 + max(left.height, right.height) } } diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.swift b/Binary Search Tree/Solution 2/BinarySearchTree.swift index 272b86368..23b1c8aca 100644 --- a/Binary Search Tree/Solution 2/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 2/BinarySearchTree.swift @@ -20,8 +20,8 @@ public enum BinarySearchTree { /* Distance of this node to its lowest leaf. Performance: O(n). */ public var height: Int { switch self { - case .empty: return 0 - case .leaf: return 1 + case .empty: return -1 + case .leaf: return 0 case let .node(left, _, right): return 1 + max(left.height, right.height) } } From 9b7ecd6a47e4522ae0b48ae4d938dc97a31f8a22 Mon Sep 17 00:00:00 2001 From: Ahmed Nader Date: Fri, 11 May 2018 23:23:20 +0200 Subject: [PATCH 096/327] Closest Pair of points algorithm --- .../ClosestPair.playground/Contents.swift | 224 ++++++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../UserInterfaceState.xcuserstate | Bin 0 -> 10014 bytes .../Images/1200px-Closest_pair_of_points.png | Bin 0 -> 17683 bytes Closest Pair/Images/Case.png | Bin 0 -> 17660 bytes Closest Pair/Images/Strip.png | Bin 0 -> 18824 bytes Closest Pair/README.markdown | 88 +++++++ 9 files changed, 331 insertions(+) create mode 100644 Closest Pair/ClosestPair.playground/Contents.swift create mode 100644 Closest Pair/ClosestPair.playground/contents.xcplayground create mode 100644 Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Closest Pair/ClosestPair.playground/playground.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 Closest Pair/Images/1200px-Closest_pair_of_points.png create mode 100644 Closest Pair/Images/Case.png create mode 100644 Closest Pair/Images/Strip.png create mode 100644 Closest Pair/README.markdown diff --git a/Closest Pair/ClosestPair.playground/Contents.swift b/Closest Pair/ClosestPair.playground/Contents.swift new file mode 100644 index 000000000..c11c1770b --- /dev/null +++ b/Closest Pair/ClosestPair.playground/Contents.swift @@ -0,0 +1,224 @@ +//Created by Ahmed Nader (github: AhmedNader42) on 4/4/18. + +func ClosestPairOf(points: [Point]) -> (minimum:Double, firstPoint:Point, secondPoint:Point) { + var innerPoints = mergeSort(points, sortAccording : true) + let result = ClosestPair(&innerPoints, innerPoints.count) + return (result.minValue, result.firstPoint, result.secondPoint) +} + +func ClosestPair(_ p : inout [Point],_ n : Int) -> (minValue: Double,firstPoint: Point,secondPoint: Point) +{ + // Brute force if only 3 points (To end recursion) + if n <= 3 + { + var i=0, j = i+1 + var minDist = Double.infinity + var newFirst:Point? = nil + var newSecond:Point? = nil + while i min { break } + if dist(strip[i], strip[x]) < temp + { + temp = dist(strip[i], strip[x]) + tempFirst = strip[i] + tempSecond = strip[x] + } + x+=1 + } + i+=1 + } + + if temp < min + { + min = temp; + first = tempFirst + second = tempSecond + } + return (min, first, second) +} + + + + +// MergeSort the array (Taken from Swift Algorithms Club with +// minor addition) +// sortAccodrding : true -> x, false -> y. +func mergeSort(_ array: [Point], sortAccording : Bool) -> [Point] { + guard array.count > 1 else { return array } + let middleIndex = array.count / 2 + let leftArray = mergeSort(Array(array[0.. [Point] { + + var compare : (Point, Point) -> Bool + + // Choose to compare with X or Y. + if sortAccording + { + compare = { p1,p2 in + return p1.x < p2.x + } + } + else + { + compare = { p1, p2 in + return p1.y < p2.y + } + } + + var leftIndex = 0 + var rightIndex = 0 + var orderedPile = [Point]() + if orderedPile.capacity < leftPile.count + rightPile.count { + orderedPile.reserveCapacity(leftPile.count + rightPile.count) + } + + while true { + guard leftIndex < leftPile.endIndex else { + orderedPile.append(contentsOf: rightPile[rightIndex.. Double +{ + let equation:Double = (((a.x-b.x)*(a.x-b.x))) + (((a.y-b.y)*(a.y-b.y))) + return equation.squareRoot() +} + + +var a = Point(0,2) +var b = Point(6,67) +var c = Point(43,71) +var d = Point(1000,1000) +var e = Point(39,107) +var f = Point(2000,2000) +var g = Point(3000,3000) +var h = Point(4000,4000) + + +var points = [a,b,c,d,e,f,g,h] +let endResult = ClosestPairOf(points: points) +print("Minimum Distance : \(endResult.minimum), The two points : (\(endResult.firstPoint.x ),\(endResult.firstPoint.y)), (\(endResult.secondPoint.x),\(endResult.secondPoint.y))") + diff --git a/Closest Pair/ClosestPair.playground/contents.xcplayground b/Closest Pair/ClosestPair.playground/contents.xcplayground new file mode 100644 index 000000000..a93d4844a --- /dev/null +++ b/Closest Pair/ClosestPair.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata b/Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate b/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..82b1303405d67c83db2a30dbba741c883e40fdff GIT binary patch literal 10014 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 A2LJ#7 literal 0 HcmV?d00001 diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown new file mode 100644 index 000000000..57786c7ff --- /dev/null +++ b/Closest Pair/README.markdown @@ -0,0 +1,88 @@ +# ClosestPair + +Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. + +![Given points and we're required to find the two red ones](../Closest Pair/Images/1200px-Closest_pair_of_points.png) + +As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? + +Here is the main algorithm (Steps) we'll follow. + +- Sort the array according to their position on the X-axis so that they are sorted in the array as they are naturally in math. + +```swift +var innerPoints = mergeSort(points, sortAccording : true) +``` + +- Divide the points into two arrays Left, Right and keep dividing until you reach to only having 3 points in your array. + +- The base case is you have less than 3 points compare those against each other (Brute force) then return the minimum distance you found and the two points. + +- Now we get the first observation in the below image, There could be 2 points both very close to each other and indeed those two are the closest pair but since our algorithm so far divides from the middle + +```swift +let line:Double = (p[mid].x + p[mid+1].x)/2 +``` + +and just recursively calls itself until it reaches the base case we don't detect those points. + +![ Points lying near the division line](../Closest Pair/Images/Case.png) + +- To solve this we start by sorting the array on the Y-axis to get the points in their natural order and then we start getting the difference between the X position of the point and the line we drew to divide and if it is less than the min we got so far from the recursion we add it to the strip + +```swift +var strip = [Point]() +var i=0, j = 0 +while i min { break } + if dist(strip[i], strip[x]) < temp + { + temp = dist(strip[i], strip[x]) + tempFirst = strip[i] + tempSecond = strip[x] + } + x+=1 + } + i+=1 + } +``` + +- Of course not every time you end up with the same shape but this is the worst case and it's rare to happen so in reality you end up with far less points valid for comparison and this is why the algorithm gets performance in addition to the sorting tricks we did. + +- Compare the points in the strip and if you find a smaller distance replace the current one with it. + + +So this is the rundown of how the algorithm works and you could see the fun little math tricks used to optimize this and we end up with O(nlogn) complexity mainly because of the sorting. + + +## See also + +See the playground to play around with the implementation of the algorithm + +[Wikipedia](https://en.wikipedia.org/wiki/Closest_pair_of_points_problem) + +*Written for Swift Algorithm Club by [Ahmed Nader](https://github.com/ahmednader42)* From 9b0a3c517d1e26ced6bd506b42af25bf2b99d287 Mon Sep 17 00:00:00 2001 From: Ahmed Nader Date: Fri, 11 May 2018 23:24:32 +0200 Subject: [PATCH 097/327] Images --- Closest Pair/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown index 57786c7ff..35ea15653 100644 --- a/Closest Pair/README.markdown +++ b/Closest Pair/README.markdown @@ -2,7 +2,7 @@ Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. -![Given points and we're required to find the two red ones](../Closest Pair/Images/1200px-Closest_pair_of_points.png) +![Given points and we're required to find the two red ones](Closest Pair/Images/1200px-Closest_pair_of_points.png) As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? @@ -26,7 +26,7 @@ let line:Double = (p[mid].x + p[mid+1].x)/2 and just recursively calls itself until it reaches the base case we don't detect those points. -![ Points lying near the division line](../Closest Pair/Images/Case.png) +![ Points lying near the division line](Closest Pair/Images/Case.png) - To solve this we start by sorting the array on the Y-axis to get the points in their natural order and then we start getting the difference between the X position of the point and the line we drew to divide and if it is less than the min we got so far from the recursion we add it to the strip @@ -46,7 +46,7 @@ while i Date: Fri, 11 May 2018 23:26:43 +0200 Subject: [PATCH 098/327] Update README.markdown --- Closest Pair/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown index 35ea15653..3ce08dd49 100644 --- a/Closest Pair/README.markdown +++ b/Closest Pair/README.markdown @@ -2,7 +2,7 @@ Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. -![Given points and we're required to find the two red ones](Closest Pair/Images/1200px-Closest_pair_of_points.png) +![Given points and we're required to find the two red ones](../Closest\ Pair/Images/1200px-Closest_pair_of_points.png) As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? From a018f72d59fd33a3990f343725dfd823f84a0340 Mon Sep 17 00:00:00 2001 From: Ahmed Nader Date: Fri, 11 May 2018 23:30:35 +0200 Subject: [PATCH 099/327] Update README.markdown --- Closest Pair/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown index 3ce08dd49..5224bcef4 100644 --- a/Closest Pair/README.markdown +++ b/Closest Pair/README.markdown @@ -2,7 +2,7 @@ Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. -![Given points and we're required to find the two red ones](../Closest\ Pair/Images/1200px-Closest_pair_of_points.png) +![Given points and we're required to find the two red ones](../Images/1200px-Closest_pair_of_points.png) As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? From 4174a840c332ee07f875306b098f710c0e3601bb Mon Sep 17 00:00:00 2001 From: Ahmed Nader Date: Fri, 11 May 2018 23:31:20 +0200 Subject: [PATCH 100/327] Update README.markdown --- Closest Pair/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown index 5224bcef4..a4de4a28b 100644 --- a/Closest Pair/README.markdown +++ b/Closest Pair/README.markdown @@ -2,7 +2,7 @@ Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. -![Given points and we're required to find the two red ones](../Images/1200px-Closest_pair_of_points.png) +![Given points and we're required to find the two red ones](Images/1200px-Closest_pair_of_points.png) As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? @@ -26,7 +26,7 @@ let line:Double = (p[mid].x + p[mid+1].x)/2 and just recursively calls itself until it reaches the base case we don't detect those points. -![ Points lying near the division line](Closest Pair/Images/Case.png) +![ Points lying near the division line](Images/Case.png) - To solve this we start by sorting the array on the Y-axis to get the points in their natural order and then we start getting the difference between the X position of the point and the line we drew to divide and if it is less than the min we got so far from the recursion we add it to the strip @@ -46,7 +46,7 @@ while i Date: Tue, 22 May 2018 11:43:26 -0700 Subject: [PATCH 101/327] Fixed broken link Link to shortest path example was broken --- Breadth-First Search/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Breadth-First Search/README.markdown b/Breadth-First Search/README.markdown index b2298822f..097f4278d 100644 --- a/Breadth-First Search/README.markdown +++ b/Breadth-First Search/README.markdown @@ -151,7 +151,7 @@ This will output: `["a", "b", "c", "d", "e", "f", "g", "h"]` Breadth-first search can be used to solve many problems. A small selection: -* Computing the [shortest path](../Shortest%20Path/) between a source node and each of the other nodes (only for unweighted graphs). +* Computing the [shortest path](../Shortest%20Path%20(Unweighted)/) between a source node and each of the other nodes (only for unweighted graphs). * Calculating the [minimum spanning tree](../Minimum%20Spanning%20Tree%20(Unweighted)/) on an unweighted graph. *Written by [Chris Pilcher](https://github.com/chris-pilcher) and Matthijs Hollemans* From bcdd28236d981f8763fdda9ebe41b699ea624579 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 4 Jun 2018 21:01:09 -0700 Subject: [PATCH 102/327] Updates maintainer list. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 919f1b67f..f5fc4247a 100644 --- a/README.markdown +++ b/README.markdown @@ -225,7 +225,7 @@ You can find the book on the [raywenderlich.com store](https://store.raywenderli The Swift Algorithm Club was originally created by [Matthijs Hollemans](https://github.com/hollance). -It is now maintained by [Vincent Ngo](https://www.raywenderlich.com/u/jomoka), [Kelvin Lau](https://github.com/kelvinlauKL) and [Ross O'brien](https://www.raywenderlich.com/u/narrativium). +It is now maintained by [Vincent Ngo](https://www.raywenderlich.com/u/jomoka), and [Kelvin Lau](https://github.com/kelvinlauKL). The Swift Algorithm Club is a collaborative effort from the [most algorithmic members](https://github.com/rwenderlich/swift-algorithm-club/graphs/contributors) of the [raywenderlich.com](https://www.raywenderlich.com) community. We're always looking for help - why not [join the club](.github/CONTRIBUTING.md)? :] From f4afbabffe020f8c81dc84a74e90e49f5ef90061 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Fri, 8 Jun 2018 01:47:25 -0700 Subject: [PATCH 103/327] Refactors first blurb. --- Myers Difference Algorithm/README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index e6137e8ce..6be30ecda 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -1,15 +1,13 @@ # Myers Difference Algorithm -Myers Difference Algorithm is an algorithm that finds a longest common subsequence(LCS) or shortest edit scripts(SES) of two sequences. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. - -For example, let's assume you have two arrays: +Myers Difference Algorithm(MDA) is an algorithm that finds a longest common subsequence(LCS) or shortest edit scripts(SES) of two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. For example, let's assume you have two arrays: ``` -A = [1, 2, 3] -B = [2, 3, 4] +let firstArray = [1, 2, 3] +let secondArray = [2, 3, 4] ``` -The common subsequences of these two arrays are `[2]`, and `[2,3]`. The longest common sequence in this case is `[2,3]`. +The common subsequences of these two arrays are `[2]`, and `[2, 3]`. The longest common sequence in this case is `[2, 3]`. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. ## Finding the length of the Longest Common Subsequence with Myers Algorithm on Edit Graph From 66db524690e73646b183eb28d3bb4ae77490b80b Mon Sep 17 00:00:00 2001 From: Ta-Cuong Nguyen Date: Sat, 9 Jun 2018 11:19:49 +0700 Subject: [PATCH 104/327] Update README.markdown Update document for Hoare's partitioning scheme --- Quicksort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Quicksort/README.markdown b/Quicksort/README.markdown index b8a908985..a9356f921 100644 --- a/Quicksort/README.markdown +++ b/Quicksort/README.markdown @@ -288,7 +288,7 @@ func partitionHoare(inout a: [T], low: Int, high: Int) -> Int { repeat { i += 1 } while a[i] < pivot if i < j { - swap(&a[i], &a[j]) + a.swapAt(i, j) } else { return j } From 22e44960a9e5f8ec0010c8ed3a3cb0d3c23c724e Mon Sep 17 00:00:00 2001 From: augustoavelino Date: Mon, 11 Jun 2018 16:29:05 -0300 Subject: [PATCH 105/327] Fixed issue in LinkedList insert(_:, at:) method where next?.previous was referencing next itself. --- Linked List/LinkedList.playground/Contents.swift | 2 +- Linked List/LinkedList.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index 4b58bb65e..cfa3a8b45 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -176,7 +176,7 @@ public final class LinkedList { list.head?.previous = prev list.last?.next = next - next?.previous = list.last?.next + next?.previous = list.last } } diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 285c85588..7c2cbb3b1 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -166,7 +166,7 @@ public final class LinkedList { list.head?.previous = prev list.last?.next = next - next?.previous = list.last?.next + next?.previous = list.last } } From 4528471976af69ce2e98dada083bd32b3fe9fd7f Mon Sep 17 00:00:00 2001 From: Denis Litvin Date: Thu, 14 Jun 2018 14:23:11 +0300 Subject: [PATCH 106/327] Fix --- Rabin-Karp/Rabin-Karp.playground/Contents.swift | 6 +++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 Rabin-Karp/Rabin-Karp.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Rabin-Karp/Rabin-Karp.playground/Contents.swift b/Rabin-Karp/Rabin-Karp.playground/Contents.swift index 739b74e2a..f5d4137c4 100644 --- a/Rabin-Karp/Rabin-Karp.playground/Contents.swift +++ b/Rabin-Karp/Rabin-Karp.playground/Contents.swift @@ -1,6 +1,6 @@ //: Taking our rabin-karp algorithm for a walk -// last checked with Xcode 9.0b4 +// last checked with Xcode 9.4 #if swift(>=4.0) print("Hello, Swift 4!") #endif @@ -30,8 +30,8 @@ extension Character { // Find first position of pattern in the text using Rabin Karp algorithm public func search(text: String, pattern: String) -> Int { // convert to array of ints - let patternArray = pattern.flatMap { $0.asInt } - let textArray = text.flatMap { $0.asInt } + let patternArray = pattern.compactMap { $0.asInt } + let textArray = text.compactMap { $0.asInt } if textArray.count < patternArray.count { return -1 diff --git a/Rabin-Karp/Rabin-Karp.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Rabin-Karp/Rabin-Karp.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Rabin-Karp/Rabin-Karp.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From bf51c93414900e44baffbb2c7bd57aca76b22909 Mon Sep 17 00:00:00 2001 From: Milad Taghavi Date: Wed, 20 Jun 2018 12:34:14 +0200 Subject: [PATCH 107/327] Add Simulated annealing to README --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index f5fc4247a..90b310752 100644 --- a/README.markdown +++ b/README.markdown @@ -119,6 +119,7 @@ Bad sorting algorithms (don't use these!): - Neural Networks - PageRank - [Naive Bayes Classifier](Naive%20Bayes%20Classifier/) +- [Simulated annealing](Simulated%20annealing/). Probabilistic technique for approximating the global maxima in a (often discrete) large search space. ## Data structures From 88f75eb2d05ff4a0e9ba18d4824158f7e9b1e84e Mon Sep 17 00:00:00 2001 From: Weslie Date: Mon, 30 Jul 2018 11:22:18 +0800 Subject: [PATCH 108/327] [Swift 4 Update]add parentheses Single argument function types require parentheses --- Binary Tree/BinaryTree.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Binary Tree/BinaryTree.swift b/Binary Tree/BinaryTree.swift index 102f23e06..6146880b4 100644 --- a/Binary Tree/BinaryTree.swift +++ b/Binary Tree/BinaryTree.swift @@ -29,7 +29,7 @@ extension BinaryTree: CustomStringConvertible { } extension BinaryTree { - public func traverseInOrder(process: T -> Void) { + public func traverseInOrder(process: (T) -> Void) { if case let .node(left, value, right) = self { left.traverseInOrder(process: process) process(value) @@ -37,7 +37,7 @@ extension BinaryTree { } } - public func traversePreOrder(process: T -> Void) { + public func traversePreOrder(process: (T) -> Void) { if case let .node(left, value, right) = self { process(value) left.traversePreOrder(process: process) @@ -45,7 +45,7 @@ extension BinaryTree { } } - public func traversePostOrder(process: T -> Void) { + public func traversePostOrder(process: (T) -> Void) { if case let .node(left, value, right) = self { left.traversePostOrder(process: process) right.traversePostOrder(process: process) From 2b932ac83689f2e29e387a763f104e47aa6ae1c2 Mon Sep 17 00:00:00 2001 From: Jen Date: Fri, 3 Aug 2018 13:57:38 -0400 Subject: [PATCH 109/327] Fixes Issue#371: Simulated Annealing demo crashes --- Simulated annealing/simann.swift | 16 ++--------- Simulated annealing/simann_example.swift | 36 +++++++----------------- 2 files changed, 13 insertions(+), 39 deletions(-) diff --git a/Simulated annealing/simann.swift b/Simulated annealing/simann.swift index 8adfbf817..5dc624d04 100644 --- a/Simulated annealing/simann.swift +++ b/Simulated annealing/simann.swift @@ -22,16 +22,6 @@ import Glibc #endif -public extension Double { - public static func random(_ lower: Double, _ upper: Double) -> Double { - #if os(OSX) - return (Double(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower - #elseif os(Linux) - return (Double(random()) / 0xFFFFFFFF) * (upper - lower) + lower - #endif - } -} - protocol Clonable { init(current: Self) } @@ -85,13 +75,13 @@ func SimulatedAnnealing(initial: T, temperature: Double, coolingRat while temp > 1 { let newSolution: T = currentSolution.clone() - let pos1: Int = Int(arc4random_uniform(UInt32(newSolution.count))) - let pos2: Int = Int(arc4random_uniform(UInt32(newSolution.count))) + let pos1: Int = Int.random(in: 0 ..< newSolution.count) + let pos2: Int = Int.random(in: 0 ..< newSolution.count) newSolution.randSwap(a: pos1, b: pos2) let currentEnergy: Double = currentSolution.currentEnergy() let newEnergy: Double = newSolution.currentEnergy() - if acceptance(currentEnergy, newEnergy, temp) > Double.random(0, 1) { + if acceptance(currentEnergy, newEnergy, temp) > Double.random(in: 0 ..< 1) { currentSolution = newSolution.clone() } if currentSolution.currentEnergy() < bestSolution.currentEnergy() { diff --git a/Simulated annealing/simann_example.swift b/Simulated annealing/simann_example.swift index a0dfaa19a..0e07e0024 100644 --- a/Simulated annealing/simann_example.swift +++ b/Simulated annealing/simann_example.swift @@ -18,21 +18,11 @@ #if os(OSX) import Foundation + import Cocoa #elseif os(Linux) import Glibc #endif -public extension Double { - - public static func random(_ lower: Double, _ upper: Double) -> Double { - #if os(OSX) - return (Double(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower - #elseif os(Linux) - return (Double(random()) / 0xFFFFFFFF) * (upper - lower) + lower - #endif - } -} - protocol Clonable { init(current: Self) } @@ -96,8 +86,8 @@ extension Point { static func <-> (left: Point, right: Point) -> Double { let xDistance = (left.x - right.x) let yDistance = (left.y - right.y) - - return Double(sqrt(Double((xDistance * xDistance) + (yDistance * yDistance)))) + + return Double((xDistance * xDistance) + (yDistance * yDistance)).squareRoot() } } @@ -128,15 +118,6 @@ extension Tour { self[a] = cpos2 self[b] = cpos1 } - - func shuffle() { - for i in stride(from: self.count - 1, through: 1, by: -1) { - let j = Int(arc4random()) % (i + 1) - if i != j { - swap(&self.tour[i], &self.tour[j]) - } - } - } func currentEnergy() -> Double { if self.energy == 0 { @@ -155,7 +136,10 @@ extension Tour { } return self.energy } - + + func shuffle() { + self.shuffle() + } } // MARK: - subscript to manipulate elements of Tour. @@ -180,13 +164,13 @@ func SimulatedAnnealing(initial: T, temperature: Double, coolingRat while temp > 1 { let newSolution: T = currentSolution.clone() - let pos1: Int = Int(arc4random_uniform(UInt32(newSolution.count))) - let pos2: Int = Int(arc4random_uniform(UInt32(newSolution.count))) + let pos1: Int = Int.random(in: 0 ..< newSolution.count) + let pos2: Int = Int.random(in: 0 ..< newSolution.count) newSolution.randSwap(a: pos1, b: pos2) let currentEnergy: Double = currentSolution.currentEnergy() let newEnergy: Double = newSolution.currentEnergy() - if acceptance(currentEnergy, newEnergy, temp) > Double.random(0, 1) { + if acceptance(currentEnergy, newEnergy, temp) > Double.random(in: 0 ..< 1) { currentSolution = newSolution.clone() } if currentSolution.currentEnergy() < bestSolution.currentEnergy() { From 8e207266be665e4a7426db2a7c30bc79bda93274 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Mon, 10 Sep 2018 20:51:35 -0700 Subject: [PATCH 110/327] Update maintainers list. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 90b310752..7d3156ae7 100644 --- a/README.markdown +++ b/README.markdown @@ -226,7 +226,7 @@ You can find the book on the [raywenderlich.com store](https://store.raywenderli The Swift Algorithm Club was originally created by [Matthijs Hollemans](https://github.com/hollance). -It is now maintained by [Vincent Ngo](https://www.raywenderlich.com/u/jomoka), and [Kelvin Lau](https://github.com/kelvinlauKL). +It is now maintained by [Vincent Ngo](https://www.raywenderlich.com/u/jomoka), [Kelvin Lau](https://github.com/kelvinlauKL), and [Richard Ash](https://github.com/richard-ash). The Swift Algorithm Club is a collaborative effort from the [most algorithmic members](https://github.com/rwenderlich/swift-algorithm-club/graphs/contributors) of the [raywenderlich.com](https://www.raywenderlich.com) community. We're always looking for help - why not [join the club](.github/CONTRIBUTING.md)? :] From 380bfc27b505ab14abd336465cade9d6ede57c57 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Wed, 26 Sep 2018 00:10:14 -0700 Subject: [PATCH 111/327] Update README.markdown Fix contributors link to point to the raywenderlich repo instead of the rwenderlich fork --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 7d3156ae7..ff8bfe778 100644 --- a/README.markdown +++ b/README.markdown @@ -228,7 +228,7 @@ The Swift Algorithm Club was originally created by [Matthijs Hollemans](https:// It is now maintained by [Vincent Ngo](https://www.raywenderlich.com/u/jomoka), [Kelvin Lau](https://github.com/kelvinlauKL), and [Richard Ash](https://github.com/richard-ash). -The Swift Algorithm Club is a collaborative effort from the [most algorithmic members](https://github.com/rwenderlich/swift-algorithm-club/graphs/contributors) of the [raywenderlich.com](https://www.raywenderlich.com) community. We're always looking for help - why not [join the club](.github/CONTRIBUTING.md)? :] +The Swift Algorithm Club is a collaborative effort from the [most algorithmic members](https://github.com/raywenderlich/swift-algorithm-club/graphs/contributors) of the [raywenderlich.com](https://www.raywenderlich.com) community. We're always looking for help - why not [join the club](.github/CONTRIBUTING.md)? :] ## License From b3ba0467b88ff48eaf6221482b05ca8908ab5bb0 Mon Sep 17 00:00:00 2001 From: Andy Ron Date: Thu, 27 Sep 2018 17:34:40 +0800 Subject: [PATCH 112/327] Update README.md --- B-Tree/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/B-Tree/README.md b/B-Tree/README.md index f6924aadc..10a06853e 100644 --- a/B-Tree/README.md +++ b/B-Tree/README.md @@ -133,7 +133,7 @@ Else: ![Moving Key](Images/MovingKey.png) -####Merging two nodes +#### Merging two nodes Let's say we want to merge the child `c1` at index `i` in its parent's children array. From 106b65ede0191fe7c6ba78fcd519334b7ea56e6a Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 1 Oct 2018 15:33:23 -0300 Subject: [PATCH 113/327] addition of Bubble sort algorithm --- .../MyPlayground.playground/Contents.swift | 27 ++++++++++++ .../Sources/BubbleSort.swift | 42 +++++++++++++++++++ .../contents.xcplayground | 4 ++ .../contents.xcworkspacedata | 7 ++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ 6 files changed, 96 insertions(+) create mode 100644 Bubble Sort/MyPlayground.playground/Contents.swift create mode 100644 Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift create mode 100644 Bubble Sort/MyPlayground.playground/contents.xcplayground create mode 100644 Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bubble Sort/MyPlayground.playground/Contents.swift b/Bubble Sort/MyPlayground.playground/Contents.swift new file mode 100644 index 000000000..d0cf07ab3 --- /dev/null +++ b/Bubble Sort/MyPlayground.playground/Contents.swift @@ -0,0 +1,27 @@ +import Foundation + +public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { + var array = elements + + for i in 0.. (_ elements: [T]) -> [T] where T: Comparable { + var array = elements + + for i in 0.. + + + \ No newline at end of file diff --git a/Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 44711ad86d5fafc1f6db40bfebb5e94e277377b1 Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 1 Oct 2018 15:57:40 -0300 Subject: [PATCH 114/327] addition of convenience method --- .../SelectionSort.playground/Contents.swift | 1 + .../Sources/SelectionSort.swift | 26 +++++++++++++++++-- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Selection Sort/SelectionSort.playground/Contents.swift b/Selection Sort/SelectionSort.playground/Contents.swift index e0bfdf259..b16dadb8d 100644 --- a/Selection Sort/SelectionSort.playground/Contents.swift +++ b/Selection Sort/SelectionSort.playground/Contents.swift @@ -6,5 +6,6 @@ print("Hello, Swift 4!") #endif let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] +selectionSort(list) selectionSort(list, <) selectionSort(list, >) diff --git a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift index 3015fde9b..b0bdfab55 100644 --- a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift +++ b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift @@ -1,4 +1,4 @@ -public func selectionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { +public func selectionSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } var a = array @@ -7,7 +7,7 @@ public func selectionSort(_ array: [T], _ isOrderedBefore: (T, T) // Find the lowest value in the rest of the array. var lowest = x for y in x + 1 ..< a.count { - if isOrderedBefore(a[y], a[lowest]) { + if a[y] < a[lowest] { lowest = y } } @@ -19,3 +19,25 @@ public func selectionSort(_ array: [T], _ isOrderedBefore: (T, T) } return a } + +public func selectionSort(_ array: [T], _ isLowerThan: (T, T) -> Bool) -> [T] { + guard array.count > 1 else { return array } + + var a = array + for x in 0 ..< a.count - 1 { + + // Find the lowest value in the rest of the array. + var lowest = x + for y in x + 1 ..< a.count { + if isLowerThan(a[y], a[lowest]) { + lowest = y + } + } + + // Swap the lowest value with the current array index. + if x != lowest { + a.swapAt(x, lowest) + } + } + return a +} diff --git a/Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From d078c50bc281d92f0369fe3b6bac5508988e175a Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 1 Oct 2018 16:02:04 -0300 Subject: [PATCH 115/327] addition of function description --- .../Sources/SelectionSort.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift index b0bdfab55..3a27ef9dd 100644 --- a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift +++ b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift @@ -1,3 +1,7 @@ +/// Performs the Selection sort algorithm on a array +/// +/// - Parameter array: array of elements that conform to the Comparable protocol +/// - Returns: an array in ascending order public func selectionSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } @@ -20,6 +24,12 @@ public func selectionSort(_ array: [T]) -> [T] { return a } +/// Performs the Selection sort algorithm on a array using the provided comparisson method +/// +/// - Parameters: +/// - array: array of elements that conform to the Comparable protocol +/// - isLowerThan: returns true if the two provided elements are in the correct order +/// - Returns: a sorted array public func selectionSort(_ array: [T], _ isLowerThan: (T, T) -> Bool) -> [T] { guard array.count > 1 else { return array } From d82954fc2c7533181c72cd800cd892a4bf7ab987 Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 1 Oct 2018 19:22:36 -0300 Subject: [PATCH 116/327] added convenience method --- .../InsertionSort.playground/Contents.swift | 35 +++++++++++++------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ Insertion Sort/InsertionSort.swift | 14 ++++++++ 3 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 Insertion Sort/InsertionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Insertion Sort/InsertionSort.playground/Contents.swift b/Insertion Sort/InsertionSort.playground/Contents.swift index 91e18640f..6c84a4a3e 100644 --- a/Insertion Sort/InsertionSort.playground/Contents.swift +++ b/Insertion Sort/InsertionSort.playground/Contents.swift @@ -6,19 +6,34 @@ print("Hello, Swift 4!") #endif func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { - var a = array - for x in 1.. 0 && isOrderedBefore(temp, a[y - 1]) { - a[y] = a[y - 1] - y -= 1 + var a = array + for x in 1.. 0 && isOrderedBefore(temp, a[y - 1]) { + a[y] = a[y - 1] + y -= 1 + } + a[y] = temp } - a[y] = temp - } - return a + return a +} + +func insertionSort(_ array: [T]) -> [T] { + var a = array + for x in 1.. 0 && temp < a[y - 1] { + a[y] = a[y - 1] + y -= 1 + } + a[y] = temp + } + return a } let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] +insertionSort(list) insertionSort(list, <) insertionSort(list, >) diff --git a/Insertion Sort/InsertionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Insertion Sort/InsertionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Insertion Sort/InsertionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Insertion Sort/InsertionSort.swift b/Insertion Sort/InsertionSort.swift index 5d8a9565b..362c8565a 100644 --- a/Insertion Sort/InsertionSort.swift +++ b/Insertion Sort/InsertionSort.swift @@ -13,3 +13,17 @@ func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { } return a } + +func insertionSort(_ array: [T]) -> [T] { + var a = array + for x in 1.. 0 && temp < a[y - 1] { + a[y] = a[y - 1] + y -= 1 + } + a[y] = temp + } + return a +} From 06e894bf80c8940fa20db172c291fa9be713350a Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 1 Oct 2018 19:26:55 -0300 Subject: [PATCH 117/327] added primitive documentation --- Insertion Sort/InsertionSort.swift | 10 ++++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 18 insertions(+) create mode 100644 Insertion Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Insertion Sort/InsertionSort.swift b/Insertion Sort/InsertionSort.swift index 362c8565a..2d623adc9 100644 --- a/Insertion Sort/InsertionSort.swift +++ b/Insertion Sort/InsertionSort.swift @@ -1,3 +1,9 @@ +/// Performs the Insertion sort algorithm to a given array +/// +/// - Parameters: +/// - array: the array of elements to be sorted +/// - isOrderedBefore: returns true if the elements provided are in the corect order +/// - Returns: a sorted array containing the same elements func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { guard array.count > 1 else { return array } @@ -14,6 +20,10 @@ func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { return a } +/// Performs the Insertion sort algorithm to a given array +/// +/// - Parameter array: the array to be sorted, conatining elements that conform to the Comparable protocol +/// - Returns: a sorted array containing the same elements func insertionSort(_ array: [T]) -> [T] { var a = array for x in 1.. + + + + IDEDidComputeMac32BitWarning + + + From 46742c7998828cf4e4ed8a49925bee046c3ae268 Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 1 Oct 2018 22:05:20 -0300 Subject: [PATCH 118/327] fixing dumb mistake --- .../InsertionSort.playground/Contents.swift | 18 +++++++++++++++--- .../contents.xcplayground | 2 +- Insertion Sort/InsertionSort.swift | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Insertion Sort/InsertionSort.playground/Contents.swift b/Insertion Sort/InsertionSort.playground/Contents.swift index 6c84a4a3e..9a10ec04a 100644 --- a/Insertion Sort/InsertionSort.playground/Contents.swift +++ b/Insertion Sort/InsertionSort.playground/Contents.swift @@ -5,7 +5,15 @@ print("Hello, Swift 4!") #endif +/// Performs the Insertion sort algorithm to a given array +/// +/// - Parameters: +/// - array: the array of elements to be sorted +/// - isOrderedBefore: returns true if the elements provided are in the corect order +/// - Returns: a sorted array containing the same elements func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { + guard array.count > 1 else { return array } + var a = array for x in 1..(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { return a } +/// Performs the Insertion sort algorithm to a given array +/// +/// - Parameter array: the array to be sorted, conatining elements that conform to the Comparable protocol +/// - Returns: a sorted array containing the same elements func insertionSort(_ array: [T]) -> [T] { var a = array for x in 1..(_ array: [T]) -> [T] { } let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] -insertionSort(list) -insertionSort(list, <) -insertionSort(list, >) +print(insertionSort(list)) +print(insertionSort(list, <)) +print(insertionSort(list, >)) diff --git a/Insertion Sort/InsertionSort.playground/contents.xcplayground b/Insertion Sort/InsertionSort.playground/contents.xcplayground index 06828af92..9f9eecc96 100644 --- a/Insertion Sort/InsertionSort.playground/contents.xcplayground +++ b/Insertion Sort/InsertionSort.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Insertion Sort/InsertionSort.swift b/Insertion Sort/InsertionSort.swift index 2d623adc9..9faf9dc42 100644 --- a/Insertion Sort/InsertionSort.swift +++ b/Insertion Sort/InsertionSort.swift @@ -25,6 +25,8 @@ func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { /// - Parameter array: the array to be sorted, conatining elements that conform to the Comparable protocol /// - Returns: a sorted array containing the same elements func insertionSort(_ array: [T]) -> [T] { + guard array.count > 1 else { return array } + var a = array for x in 1.. Date: Tue, 2 Oct 2018 11:49:32 -0300 Subject: [PATCH 119/327] correction in the algorithm --- .../MyPlayground.playground/Contents.swift | 16 ++++++---------- .../Sources/BubbleSort.swift | 8 ++++---- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Bubble Sort/MyPlayground.playground/Contents.swift b/Bubble Sort/MyPlayground.playground/Contents.swift index d0cf07ab3..16466e0bc 100644 --- a/Bubble Sort/MyPlayground.playground/Contents.swift +++ b/Bubble Sort/MyPlayground.playground/Contents.swift @@ -4,10 +4,11 @@ public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { var array = elements for i in 0.. (_ elements: [T]) -> [T] where T: Comparable { return array } - -var array = [Int]() - -for _ in 0...10 { - array.append(Int.random(in: 0...500)) -} +var array = [4,2,1,3] print("before:",array) print("after:",BubbleSort(array)) diff --git a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift index 8f1ec80f8..5ce18ef9b 100644 --- a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift +++ b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift @@ -29,10 +29,10 @@ public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { var array = elements for i in 0.. Date: Tue, 2 Oct 2018 13:36:20 -0300 Subject: [PATCH 120/327] added imlementation information on readme --- Bubble Sort/README.markdown | 72 ++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index 93d370827..80161ce56 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -1,6 +1,6 @@ # Bubble Sort -Bubble sort is a sorting algorithm that is implemented by starting in the beginning of the array and swapping the first two elements only if the first element is greater than the second element. This comparison is then moved onto the next pair and so on and so forth. This is done until the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array. +Bubble sort is a sorting algorithm that is implemented by starting in the beginning of the array and swapping the first two elements only if the first element is greater than the second element. This comparison is then moved onto the next pair and so on and so forth. This is done until the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array.Sometimes this algorithm is refered as Sinking sort, due to the larger, or heavier elements sinking to the end of the array. ##### Runtime: - Average: O(N^2) @@ -12,3 +12,73 @@ Bubble sort is a sorting algorithm that is implemented by starting in the beginn ### Implementation: The implementation will not be shown as the average and worst runtimes show that this is a very inefficient algorithm. However, having a grasp of the concept will help you understand the basics of simple sorting algorithms. + +Bubble sort is a very simple sorting algorithm, it consists in comparing pairs of adjacent elements in the array, if the first element is larger, swap them, otherwise, you do nothing and go for the next comparison. +This is accomplished by looking through the array `n` times, `n` being the amount of elements in the array. + +#### Example +Let us take the array `[5, 1, 4, 2, 8]`, and sort the array from lowest number to greatest number using bubble sort. In each step, elements written in bold are being compared. Three passes will be required. + +##### First Pass +[ **5 1** 4 2 8 ] -> [ **1 5** 4 2 8 ], Here, algorithm compares the first two elements, and swaps since 5 > 1. + +[ 1 **5 4** 2 8 ] -> [ 1 **4 5** 2 8 ], Swap since 5 > 4 + +[ 1 4 **5 2** 8 ] -> [ 1 4 **2 5** 8 ], Swap since 5 > 2 + +[ 1 4 2 **5 8** ] -> [ 1 4 2 **5 8** ], Now, since these elements are already in order (8 > 5), algorithm does not swap them. + +##### Second Pass +[ **1 4** 2 5 8 ] -> [ **1 4** 2 5 8 ] + +[ 1 **4 2** 5 8 ] -> [ 1 **2 4** 5 8 ], Swap since 4 > 2 + +[ 1 2 **4 5** 8 ] -> [ 1 2 **4 5** 8 ] + +[ 1 2 4 **5 8** ] -> [ 1 2 4 **5 8** ] +Now, the array is already sorted, but the algorithm does not know if it is completed. The algorithm needs one whole pass without any swap to know it is sorted. + +##### Third Pass +[ **1 2** 4 5 8 ] -> [ **1 2** 4 5 8 ] + +[ 1 **2 4** 5 8 ] -> [ 1 **2 4** 5 8 ] + +[ 1 2 **4 5** 8 ] -> [ 1 2 **4 5** 8 ] + +[ 1 2 4 **5 8** ] -> [ 1 2 4 **5 8** ] + +This is the same for the forth and fifth passes. + +#### Code +```swift +for i in 0.. Date: Wed, 3 Oct 2018 21:35:49 +0300 Subject: [PATCH 121/327] [Swift 4.2] Update Binary Search --- Binary Search/BinarySearch.playground/Contents.swift | 5 ----- Binary Search/BinarySearch.playground/contents.xcplayground | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Binary Search/BinarySearch.playground/Contents.swift b/Binary Search/BinarySearch.playground/Contents.swift index 715fb5dc2..f673f25c4 100644 --- a/Binary Search/BinarySearch.playground/Contents.swift +++ b/Binary Search/BinarySearch.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // An unsorted array of numbers let numbers = [11, 59, 3, 2, 53, 17, 31, 7, 19, 67, 47, 13, 37, 61, 29, 43, 5, 41, 23] diff --git a/Binary Search/BinarySearch.playground/contents.xcplayground b/Binary Search/BinarySearch.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Binary Search/BinarySearch.playground/contents.xcplayground +++ b/Binary Search/BinarySearch.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From 7457400c6df02091f0943296335933a4645e58e1 Mon Sep 17 00:00:00 2001 From: Daniil Subbotin Date: Wed, 3 Oct 2018 22:06:41 +0300 Subject: [PATCH 122/327] [Swift 4.2] Update Shuffle --- Shuffle/README.markdown | 8 ++------ Shuffle/Shuffle.playground/Contents.swift | 5 ----- Shuffle/Shuffle.playground/Sources/Shuffle.swift | 9 ++------- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/Shuffle/README.markdown b/Shuffle/README.markdown index ced138572..63868767b 100644 --- a/Shuffle/README.markdown +++ b/Shuffle/README.markdown @@ -33,8 +33,6 @@ You should see three different arrangements -- or [permutations](../Combinatoric This shuffle works *in place*, it modifies the contents of the original array. The algorithm works by creating a new array, `temp`, that is initially empty. Then we randomly choose an element from the original array and append it to `temp`, until the original array is empty. Finally, the temporary array is copied back into the original one. -> **Note:** `random()` is a helper function that returns a random integer between 0 and the given maximum. - This code works just fine but it's not very efficient. Removing an element from an array is an **O(n)** operation and we perform this **n** times, making the total algorithm **O(n^2)**. We can do better! ## The Fisher-Yates / Knuth shuffle @@ -45,7 +43,7 @@ Here is a much improved version of the shuffle algorithm: extension Array { public mutating func shuffle() { for i in stride(from: count - 1, through: 1, by: -1) { - let j = random(i + 1) + let j = Int.random(in: 0...i) if i != j { swap(&self[i], &self[j]) } @@ -56,8 +54,6 @@ extension Array { Again, this picks objects at random. In the naive version we placed those objects into a new temporary array so we could keep track of which objects were already shuffled and which still remained to be done. In this improved algorithm, however, we'll move the shuffled objects to the end of the original array. -> **Note**: When you write `random(x)`, the largest number it will return is `x - 1`. We want to have `j <= i`, not `j < i`, so the largest number from the random number generator needs to be `i`, not `i - 1`. That's why we do `random(i + 1)`. If we didn't add that 1 to compensate, it would make some shuffle orders more likely to occur than others. - Let's walk through the example. We have the array: [ "a", "b", "c", "d", "e", "f", "g" ] @@ -99,7 +95,7 @@ Here is the code: public func shuffledArray(_ n: Int) -> [Int] { var a = [Int](repeating: 0, count: n) for i in 0..=4.0) -print("Hello, Swift 4!") -#endif - import Foundation var list = [ "a", "b", "c", "d", "e", "f", "g" ] diff --git a/Shuffle/Shuffle.playground/Sources/Shuffle.swift b/Shuffle/Shuffle.playground/Sources/Shuffle.swift index 553832d43..500d3c245 100644 --- a/Shuffle/Shuffle.playground/Sources/Shuffle.swift +++ b/Shuffle/Shuffle.playground/Sources/Shuffle.swift @@ -1,10 +1,5 @@ import Foundation -/* Returns a random integer between 0 and n-1. */ -public func random(_ n: Int) -> Int { - return Int(arc4random_uniform(UInt32(n))) -} - extension Array { /* Randomly shuffles the array in-place @@ -13,7 +8,7 @@ extension Array { */ public mutating func shuffle() { for i in (1...count-1).reversed() { - let j = random(i + 1) + let j = Int.random(in: 0...i) if i != j { let t = self[i] self[i] = self[j] @@ -29,7 +24,7 @@ extension Array { public func shuffledArray(_ n: Int) -> [Int] { var a = Array(repeating: 0, count: n) for i in 0.. Date: Wed, 3 Oct 2018 21:49:24 -0700 Subject: [PATCH 123/327] [Swift 4.2] Update Stack --- Stack/Stack.playground/Contents.swift | 6 ------ Stack/Stack.playground/contents.xcplayground | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index e9e3e9a57..1eb705f20 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -1,9 +1,3 @@ - -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - /* Stack diff --git a/Stack/Stack.playground/contents.xcplayground b/Stack/Stack.playground/contents.xcplayground index 5da2641c9..a40c0f554 100644 --- a/Stack/Stack.playground/contents.xcplayground +++ b/Stack/Stack.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From c2d0169719cf1c76533c9402fcd96248e3e6978e Mon Sep 17 00:00:00 2001 From: Ashish Kakkad Date: Thu, 4 Oct 2018 22:07:39 +0530 Subject: [PATCH 124/327] Swift 4.2 [Array2D] --- Array2D/Array2D.playground/Contents.swift | 5 ----- Array2D/Tests/Tests.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Array2D/Array2D.playground/Contents.swift b/Array2D/Array2D.playground/Contents.swift index 77c0b364c..d31d77540 100644 --- a/Array2D/Array2D.playground/Contents.swift +++ b/Array2D/Array2D.playground/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - /* Two-dimensional array with a fixed number of rows and columns. This is mostly handy for games that are played on a grid, such as chess. diff --git a/Array2D/Tests/Tests.xcodeproj/project.pbxproj b/Array2D/Tests/Tests.xcodeproj/project.pbxproj index a0fb1480b..af9b7c3b8 100644 --- a/Array2D/Tests/Tests.xcodeproj/project.pbxproj +++ b/Array2D/Tests/Tests.xcodeproj/project.pbxproj @@ -226,7 +226,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -238,7 +238,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; From c7d17128ccda1f80da11e85e5a381102e1fab8c6 Mon Sep 17 00:00:00 2001 From: Ashish Kakkad Date: Thu, 4 Oct 2018 22:51:29 +0530 Subject: [PATCH 125/327] [Swift 4.2] Graph --- Graph/Graph.playground/Contents.swift | 6 ------ Graph/Graph.playground/timeline.xctimeline | 2 +- Graph/Graph.xcodeproj/project.pbxproj | 14 +++++++++----- .../xcshareddata/xcschemes/Graph.xcscheme | 2 +- .../xcshareddata/xcschemes/GraphTests.xcscheme | 2 +- Graph/GraphTests/GraphTests.swift | 7 ------- 6 files changed, 12 insertions(+), 21 deletions(-) diff --git a/Graph/Graph.playground/Contents.swift b/Graph/Graph.playground/Contents.swift index 0410942f8..fde396e64 100644 --- a/Graph/Graph.playground/Contents.swift +++ b/Graph/Graph.playground/Contents.swift @@ -1,11 +1,5 @@ import Graph -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - - for graph in [AdjacencyMatrixGraph(), AdjacencyListGraph()] { let v1 = graph.createVertex(1) diff --git a/Graph/Graph.playground/timeline.xctimeline b/Graph/Graph.playground/timeline.xctimeline index 6afe06b6f..59717856a 100644 --- a/Graph/Graph.playground/timeline.xctimeline +++ b/Graph/Graph.playground/timeline.xctimeline @@ -3,7 +3,7 @@ version = "3.0"> diff --git a/Graph/Graph.xcodeproj/project.pbxproj b/Graph/Graph.xcodeproj/project.pbxproj index 17a5a7d6b..790f6ac18 100644 --- a/Graph/Graph.xcodeproj/project.pbxproj +++ b/Graph/Graph.xcodeproj/project.pbxproj @@ -158,7 +158,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 49BFA2FC1CDF886B00522D66 = { @@ -251,12 +251,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -289,7 +291,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -308,12 +310,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -339,7 +343,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -364,7 +368,7 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -386,7 +390,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme index a12d85dad..73524effc 100644 --- a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme +++ b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme @@ -1,6 +1,6 @@ =4.0) - print("Hello, Swift 4!") - #endif - } - func testAdjacencyMatrixGraphDescription() { let graph = AdjacencyMatrixGraph() From 7442c10f596fec191eacbec644fcf8d5fae7f30a Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Thu, 4 Oct 2018 22:34:48 +0500 Subject: [PATCH 126/327] Update Z-Algorithm up to Swift 4.2. --- Z-Algorithm/README.markdown | 5 ++--- Z-Algorithm/ZAlgorithm.swift | 3 +-- Z-Algorithm/ZetaAlgorithm.playground/Contents.swift | 10 ++-------- Z-Algorithm/ZetaAlgorithm.swift | 2 +- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/Z-Algorithm/README.markdown b/Z-Algorithm/README.markdown index 8b84c28bf..a6423be03 100644 --- a/Z-Algorithm/README.markdown +++ b/Z-Algorithm/README.markdown @@ -28,8 +28,7 @@ This a simple description of the idea that is behind this algorithm. There are a Here is the code of the function that computes the Z-array: ```swift func ZetaAlgorithm(ptrn: String) -> [Int]? { - - let pattern = Array(ptrn.characters) + let pattern = Array(ptrn) let patternLength: Int = pattern.count guard patternLength > 0 else { @@ -131,7 +130,7 @@ The Z-Algorithm discussed above leads to the simplest linear-time string matchin extension String { func indexesOf(pattern: String) -> [Int]? { - let patternLength: Int = pattern.characters.count + let patternLength: Int = pattern.count /* Let's calculate the Z-Algorithm on the concatenation of pattern and text */ let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) diff --git a/Z-Algorithm/ZAlgorithm.swift b/Z-Algorithm/ZAlgorithm.swift index 969a3599b..65acaabd1 100644 --- a/Z-Algorithm/ZAlgorithm.swift +++ b/Z-Algorithm/ZAlgorithm.swift @@ -9,8 +9,7 @@ import Foundation func ZetaAlgorithm(ptrn: String) -> [Int]? { - - let pattern = Array(ptrn.characters) + let pattern = Array(ptrn) let patternLength = pattern.count guard patternLength > 0 else { diff --git a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift index d057080a1..56aa92170 100644 --- a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift +++ b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift @@ -1,13 +1,7 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - func ZetaAlgorithm(ptrn: String) -> [Int]? { - - let pattern = Array(ptrn.characters) + let pattern = Array(ptrn) let patternLength = pattern.count guard patternLength > 0 else { @@ -65,7 +59,7 @@ func ZetaAlgorithm(ptrn: String) -> [Int]? { extension String { func indexesOf(pattern: String) -> [Int]? { - let patternLength = pattern.characters.count + let patternLength = pattern.count let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) guard zeta != nil else { diff --git a/Z-Algorithm/ZetaAlgorithm.swift b/Z-Algorithm/ZetaAlgorithm.swift index e60c1617f..f2c453364 100644 --- a/Z-Algorithm/ZetaAlgorithm.swift +++ b/Z-Algorithm/ZetaAlgorithm.swift @@ -11,7 +11,7 @@ import Foundation extension String { func indexesOf(pattern: String) -> [Int]? { - let patternLength = pattern.characters.count + let patternLength = pattern.count let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) guard zeta != nil else { From 3c3168ea6e8d01972727d8db5ebea10f4aa794d3 Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Thu, 4 Oct 2018 23:13:45 +0500 Subject: [PATCH 127/327] Update Deque up to Swift 4.2. --- Deque/Deque-Simple.swift | 2 +- Deque/Deque.playground/Contents.swift | 5 ----- Deque/README.markdown | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Deque/Deque-Simple.swift b/Deque/Deque-Simple.swift index f4f5f0409..fc0fcb2b2 100644 --- a/Deque/Deque-Simple.swift +++ b/Deque/Deque-Simple.swift @@ -21,7 +21,7 @@ public struct Deque { } public mutating func enqueueFront(_ element: T) { - array.insert(element, atIndex: 0) + array.insert(element, at: 0) } public mutating func dequeue() -> T? { diff --git a/Deque/Deque.playground/Contents.swift b/Deque/Deque.playground/Contents.swift index df9b57a5e..9e7b22c02 100644 --- a/Deque/Deque.playground/Contents.swift +++ b/Deque/Deque.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - public struct Deque { private var array = [T]() diff --git a/Deque/README.markdown b/Deque/README.markdown index fda1de5f8..f3172e16e 100644 --- a/Deque/README.markdown +++ b/Deque/README.markdown @@ -23,7 +23,7 @@ public struct Deque { } public mutating func enqueueFront(_ element: T) { - array.insert(element, atIndex: 0) + array.insert(element, at: 0) } public mutating func dequeue() -> T? { From ed155f211d5b98fc54e3de40b55680367b5e1e93 Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Thu, 4 Oct 2018 23:21:00 +0500 Subject: [PATCH 128/327] Remove notice from GCD playground. --- GCD/GCD.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/GCD/GCD.playground/Contents.swift b/GCD/GCD.playground/Contents.swift index f0fceb0da..c44f28310 100644 --- a/GCD/GCD.playground/Contents.swift +++ b/GCD/GCD.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // Recursive version func gcd(_ a: Int, _ b: Int) -> Int { let r = a % b From 945c7cbe8e6f79dd31f4e0f3468d22d0f5f024c2 Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Thu, 4 Oct 2018 23:28:36 +0500 Subject: [PATCH 129/327] Remove notice from FixedSizeArray playground. --- Fixed Size Array/FixedSizeArray.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Fixed Size Array/FixedSizeArray.playground/Contents.swift b/Fixed Size Array/FixedSizeArray.playground/Contents.swift index 8b5bc1147..616f8443d 100644 --- a/Fixed Size Array/FixedSizeArray.playground/Contents.swift +++ b/Fixed Size Array/FixedSizeArray.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - /* An unordered array with a maximum size. From 8ea8a6590457b2ba931444ea75506e329850e788 Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Thu, 4 Oct 2018 23:34:40 +0500 Subject: [PATCH 130/327] Update Insertion Sort up to Swift 4.2. --- .../InsertionSort.playground/Contents.swift | 5 ---- .../Tests/Tests.xcodeproj/project.pbxproj | 26 ++++++++++++++++--- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Insertion Sort/InsertionSort.playground/Contents.swift b/Insertion Sort/InsertionSort.playground/Contents.swift index 9a10ec04a..184fc36e4 100644 --- a/Insertion Sort/InsertionSort.playground/Contents.swift +++ b/Insertion Sort/InsertionSort.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - /// Performs the Insertion sort algorithm to a given array /// /// - Parameters: diff --git a/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj b/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj index ee3ca1cae..e9ea3bc53 100644 --- a/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -86,12 +86,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0800; + LastSwiftMigration = 1000; }; }; }; @@ -145,14 +145,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -191,14 +199,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -230,7 +246,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -242,7 +259,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 14f27f777..afd69e6a7 100644 --- a/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 4 Oct 2018 20:49:35 +0200 Subject: [PATCH 131/327] Update project with Xcode 10. --- .../Tests/Tests.xcodeproj/project.pbxproj | 24 +++++++++++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj b/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj index 6493fd153..f0649ba26 100644 --- a/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj +++ b/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj @@ -83,12 +83,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0800; + LastSwiftMigration = 1000; }; }; }; @@ -141,14 +141,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -188,14 +196,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -228,7 +244,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -240,7 +256,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 14f27f777..afd69e6a7 100644 --- a/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 4 Oct 2018 20:50:05 +0200 Subject: [PATCH 132/327] Remove use of deprecated `characters` property. --- Bloom Filter/Tests/BloomFilterTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bloom Filter/Tests/BloomFilterTests.swift b/Bloom Filter/Tests/BloomFilterTests.swift index 30df702a7..d88ec0a31 100644 --- a/Bloom Filter/Tests/BloomFilterTests.swift +++ b/Bloom Filter/Tests/BloomFilterTests.swift @@ -6,7 +6,7 @@ import XCTest func djb2(_ x: String) -> Int { var hash = 5381 - for char in x.characters { + for char in x { hash = ((hash << 5) &+ hash) &+ char.hashValue } @@ -16,7 +16,7 @@ func djb2(_ x: String) -> Int { func sdbm(_ x: String) -> Int { var hash = 0 - for char in x.characters { + for char in x { hash = char.hashValue &+ (hash << 6) &+ (hash << 16) &- hash } From 6ef7a6e6ad07781320418d276a67eaa4e3d635d7 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 4 Oct 2018 20:57:46 +0200 Subject: [PATCH 133/327] Xcode 10 automated changes. --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Bloom Filter/BloomFilter.playground/timeline.xctimeline | 6 ------ 2 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Bloom Filter/BloomFilter.playground/timeline.xctimeline diff --git a/Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bloom Filter/BloomFilter.playground/timeline.xctimeline b/Bloom Filter/BloomFilter.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Bloom Filter/BloomFilter.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - From 4201fb4fc8bfefe4ab9651f5c393c55ddfd5f294 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 4 Oct 2018 20:58:26 +0200 Subject: [PATCH 134/327] Update for Swift 4.2. * Remove the top code snippet, as per instructions. * Remove use of deprecated `characters` property. --- Bloom Filter/BloomFilter.playground/Contents.swift | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Bloom Filter/BloomFilter.playground/Contents.swift b/Bloom Filter/BloomFilter.playground/Contents.swift index 9e4a89351..7a3719d57 100644 --- a/Bloom Filter/BloomFilter.playground/Contents.swift +++ b/Bloom Filter/BloomFilter.playground/Contents.swift @@ -1,8 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif + public class BloomFilter { fileprivate var array: [Bool] private var hashFunctions: [(T) -> Int] @@ -54,7 +51,7 @@ public class BloomFilter { func djb2(x: String) -> Int { var hash = 5381 - for char in x.characters { + for char in x { hash = ((hash << 5) &+ hash) &+ char.hashValue } return Int(hash) @@ -62,7 +59,7 @@ func djb2(x: String) -> Int { func sdbm(x: String) -> Int { var hash = 0 - for char in x.characters { + for char in x { hash = char.hashValue &+ (hash << 6) &+ (hash << 16) &- hash } return Int(hash) From 849309c5eb5d2ef29918940536cc1b011b665b3c Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 4 Oct 2018 21:45:50 +0200 Subject: [PATCH 135/327] Add note about Hasher in README. * Adds a section about another Bloom filter approach, using only a single hashing function with Swift 4.2's `Hasher`. * Adds links to some more documentation and a blog post implementing the Bloom filter in this way. * Adds my name as updater. --- Bloom Filter/README.markdown | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Bloom Filter/README.markdown b/Bloom Filter/README.markdown index 3fff0a379..4364db857 100644 --- a/Bloom Filter/README.markdown +++ b/Bloom Filter/README.markdown @@ -100,4 +100,29 @@ public func query(_ value: T) -> Bool { If you're coming from another imperative language, you might notice the unusual syntax in the `exists` assignment. Swift makes use of functional paradigms when it makes code more consise and readable, and in this case `reduce` is a much more consise way to check if all the required bits are `true` than a `for` loop. -*Written for Swift Algorithm Club by Jamil Dhanani. Edited by Matthijs Hollemans.* +## Another approach + +Another approach to create different hashes of an element for use in the Bloom filter, is to use the same hash function for every iteration, but combine it with different random numbers. This can help, because finding good hashing functions is hard, but combining them is equally non-trivial. + +``` +hash("Hello world!") >> hash(987654321) // would flip bit 8 +hash("Hello world!") >> hash(123456789) // would flip bit 2 +``` + +Since Swift 4.2, `Hasher` is now included in the Standard library, which is designed to reduce multiple hashes to a single hash in an efficient manner. This makes combining the hashes trivial. + +``` +private func computeHashes(_ value: T) -> [Int] { + return randomSeeds.map() { seed in + let hasher = Hasher() + hasher.combine(seed) + hasher.combine(value) + let hashValue = hasher.finalize() + return abs(hashValue % array.count) + } +} +``` + +If you want to learn more about this approach, you can read about the [Hasher documentation](https://developer.apple.com/documentation/swift/hasher) or Soroush Khanlou's [Swift 4.2 Bloom filter](http://khanlou.com/2018/09/bloom-filters/) implementation. + +*Written for Swift Algorithm Club by Jamil Dhanani. Edited by Matthijs Hollemans. Updated by Bruno Scheele.* From a56b88370d49aaf0d5640ca59d955f61178108f8 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 21:33:32 -0400 Subject: [PATCH 136/327] [Swift 4.2] Update Binary Search Tree --- .../Contents.swift | 5 -- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ .../Tests/Tests.xcodeproj/project.pbxproj | 47 ++++++++++++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- .../Contents.swift | 5 -- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ .../Sources/BinarySearch.swift | 52 ------------------- .../contents.xcworkspacedata | 7 --- 9 files changed, 64 insertions(+), 78 deletions(-) create mode 100644 Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Binary Search/BinarySearch.playground/Sources/BinarySearch.swift delete mode 100644 Binary Search/BinarySearch.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift index 8c06ae9e1..ec9902283 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let tree = BinarySearchTree(value: 7) tree.insert(value: 2) tree.insert(value: 5) diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj index f4c3f65c7..ff594fff8 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ @@ -83,17 +83,17 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0820; + LastSwiftMigration = 1000; }; }; }; buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 10.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -141,13 +141,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -185,13 +195,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -210,6 +230,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; @@ -218,10 +239,15 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -230,10 +256,15 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..afd69e6a7 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ =4.0) -print("Hello, Swift 4!") -#endif - // Each time you insert something, you get back a completely new tree. var tree = BinarySearchTree.leaf(7) tree = tree.insert(newValue: 2) diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search/BinarySearch.playground/Sources/BinarySearch.swift b/Binary Search/BinarySearch.playground/Sources/BinarySearch.swift deleted file mode 100644 index d6623e355..000000000 --- a/Binary Search/BinarySearch.playground/Sources/BinarySearch.swift +++ /dev/null @@ -1,52 +0,0 @@ -/** - Binary Search - - Recursively splits the array in half until the value is found. - - If there is more than one occurrence of the search key in the array, then - there is no guarantee which one it finds. - - Note: The array must be sorted! - **/ - -import Foundation - -// The recursive version of binary search. - -public func binarySearch(_ a: [T], key: T, range: Range) -> Int? { - if range.lowerBound >= range.upperBound { - return nil - } else { - let midIndex = range.lowerBound + (range.upperBound - range.lowerBound) / 2 - if a[midIndex] > key { - return binarySearch(a, key: key, range: range.lowerBound ..< midIndex) - } else if a[midIndex] < key { - return binarySearch(a, key: key, range: midIndex + 1 ..< range.upperBound) - } else { - return midIndex - } - } -} - -/** - The iterative version of binary search. - - Notice how similar these functions are. The difference is that this one - uses a while loop, while the other calls itself recursively. - **/ - -public func binarySearch(_ a: [T], key: T) -> Int? { - var lowerBound = 0 - var upperBound = a.count - while lowerBound < upperBound { - let midIndex = lowerBound + (upperBound - lowerBound) / 2 - if a[midIndex] == key { - return midIndex - } else if a[midIndex] < key { - lowerBound = midIndex + 1 - } else { - upperBound = midIndex - } - } - return nil -} diff --git a/Binary Search/BinarySearch.playground/playground.xcworkspace/contents.xcworkspacedata b/Binary Search/BinarySearch.playground/playground.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Binary Search/BinarySearch.playground/playground.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - From 54ac83543efd7bb47d1a976fcf9016ac618c3793 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 21:38:01 -0400 Subject: [PATCH 137/327] [Swift 4.2] Update Binary Search Tree --- .../Contents.swift | 5 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ---- .../Tests/Tests.xcodeproj/project.pbxproj | 47 ++++--------------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ---- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- .../Contents.swift | 5 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ---- 7 files changed, 19 insertions(+), 64 deletions(-) delete mode 100644 Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift index ec9902283..8c06ae9e1 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift @@ -1,5 +1,10 @@ //: Playground - noun: a place where people can play +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + let tree = BinarySearchTree(value: 7) tree.insert(value: 2) tree.insert(value: 5) diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj index ff594fff8..f4c3f65c7 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 46; objects = { /* Begin PBXBuildFile section */ @@ -83,17 +83,17 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 1000; + LastUpgradeCheck = 0720; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 1000; + LastSwiftMigration = 0820; }; }; }; buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; - compatibilityVersion = "Xcode 10.0"; + compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -141,23 +141,13 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -195,23 +185,13 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -230,7 +210,6 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; @@ -239,15 +218,10 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/../Frameworks", - ); + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -256,15 +230,10 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/../Frameworks", - ); + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index afd69e6a7..8ef8d8581 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ =4.0) +print("Hello, Swift 4!") +#endif + // Each time you insert something, you get back a completely new tree. var tree = BinarySearchTree.leaf(7) tree = tree.insert(newValue: 2) diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - From d6099b34226cef00bc5e83fa503437c88fbd39b2 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 21:38:36 -0400 Subject: [PATCH 138/327] [Swift 4.2] Dijkstra Algorithm --- Dijkstra Algorithm/Dijkstra.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../VisualizedDijkstra.playground/Contents.swift | 5 ----- .../VisualizedDijkstra.playground/Sources/Window.swift | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 5 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift index 1cd1254b1..7c7f1a4b0 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift @@ -1,11 +1,6 @@ //: Playground - noun: a place where people can play import Foundation -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - var vertices: Set = Set() func createNotConnectedVertices() { diff --git a/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift index 8e61ef49b..de6b49834 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift @@ -9,11 +9,6 @@ import UIKit import PlaygroundSupport -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - /*: First of all, let's set up colors for our window and graph. The visited color will be applied to visited vertices. The checking color will be applied to an edge and an edge neighbor every time the algorithm is checking some vertex neighbors. And default colors are just initial colors for elements. */ diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift index 73c512e6b..9a169b8c7 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift @@ -134,7 +134,7 @@ public class Window: UIView, GraphDelegate { let origin = CGPoint(x: center.x - 25, y: 100) let activityIndicatorFrame = CGRect(origin: origin, size: size) activityIndicator = UIActivityIndicatorView(frame: activityIndicatorFrame) - activityIndicator.activityIndicatorViewStyle = .whiteLarge + activityIndicator.style = .whiteLarge } @objc private func createGraphButtonTap() { diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From e6a2aa77f23a515081d8bc806e46efc81d785321 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 21:43:56 -0400 Subject: [PATCH 139/327] [Swift 4.2] Update Binary Search Tree --- .../Contents.swift | 5 --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../Tests/Tests.xcodeproj/project.pbxproj | 31 ++++++++++++++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- .../Contents.swift | 5 --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ 7 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift index 8c06ae9e1..ec9902283 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let tree = BinarySearchTree(value: 7) tree.insert(value: 2) tree.insert(value: 5) diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj index f4c3f65c7..d7c687e0c 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj @@ -83,12 +83,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0820; + LastSwiftMigration = 1000; }; }; }; @@ -141,13 +141,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -185,13 +195,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -210,6 +230,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; @@ -221,7 +242,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -233,7 +255,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..afd69e6a7 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ =4.0) -print("Hello, Swift 4!") -#endif - // Each time you insert something, you get back a completely new tree. var tree = BinarySearchTree.leaf(7) tree = tree.insert(newValue: 2) diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 1d452b31d82f06ad964ae5acd6d0bd7e8b2cadd8 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 22:01:22 -0400 Subject: [PATCH 140/327] [Swift 4.2] Queue --- Queue/Tests/Tests.xcodeproj/project.pbxproj | 26 ++++++++++++++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Queue/Tests/Tests.xcodeproj/project.pbxproj b/Queue/Tests/Tests.xcodeproj/project.pbxproj index a554fd16e..f7fc3e048 100644 --- a/Queue/Tests/Tests.xcodeproj/project.pbxproj +++ b/Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -83,12 +83,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0800; + LastSwiftMigration = 1000; }; }; }; @@ -141,14 +141,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -187,14 +195,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -226,7 +242,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -238,7 +255,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 14f27f777..afd69e6a7 100644 --- a/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 4 Oct 2018 22:05:37 -0400 Subject: [PATCH 141/327] [Swift 4.2] Queue --- Queue/Queue.playground/Contents.swift | 6 ------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Queue/Tests/Tests.xcodeproj/project.pbxproj | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Queue/Queue.playground/Contents.swift b/Queue/Queue.playground/Contents.swift index 22d2a84ca..08327783f 100644 --- a/Queue/Queue.playground/Contents.swift +++ b/Queue/Queue.playground/Contents.swift @@ -1,9 +1,3 @@ - -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - /* Queue diff --git a/Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Queue/Tests/Tests.xcodeproj/project.pbxproj b/Queue/Tests/Tests.xcodeproj/project.pbxproj index f7fc3e048..f927aba0d 100644 --- a/Queue/Tests/Tests.xcodeproj/project.pbxproj +++ b/Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -242,7 +242,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.2; }; name = Debug; @@ -255,7 +255,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.2; }; name = Release; From 01ba34cc5084c7f70beb3955d71918f75fb30bd0 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 22:17:58 -0400 Subject: [PATCH 142/327] [Swift 4.2] Merge Sort --- Merge Sort/MergeSort.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Merge Sort/MergeSort.playground/Contents.swift b/Merge Sort/MergeSort.playground/Contents.swift index b05332bfe..ca1347890 100644 --- a/Merge Sort/MergeSort.playground/Contents.swift +++ b/Merge Sort/MergeSort.playground/Contents.swift @@ -1,10 +1,5 @@ /* Top-down recursive version */ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - func mergeSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } let middleIndex = array.count / 2 diff --git a/Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 3f0bdc6ec0009bf08251458a04b11631d13cb7c7 Mon Sep 17 00:00:00 2001 From: danielchick Date: Thu, 4 Oct 2018 22:44:53 -0500 Subject: [PATCH 143/327] [Swift 4.2] Update Tree --- Tree/Tree.playground/Contents.swift | 4 ++-- Tree/Tree.playground/contents.xcplayground | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tree/Tree.playground/Contents.swift b/Tree/Tree.playground/Contents.swift index 49cf41054..06f992fa8 100644 --- a/Tree/Tree.playground/Contents.swift +++ b/Tree/Tree.playground/Contents.swift @@ -1,8 +1,8 @@ //: Playground - noun: a place where people can play // last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") +#if swift(>=4.2) +print("Hello, Swift 4.2!") #endif let tree = TreeNode(value: "beverages") diff --git a/Tree/Tree.playground/contents.xcplayground b/Tree/Tree.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Tree/Tree.playground/contents.xcplayground +++ b/Tree/Tree.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From f24a004b0420dcd3dc3156b368852e30b9841e89 Mon Sep 17 00:00:00 2001 From: imvm Date: Fri, 5 Oct 2018 02:51:06 -0300 Subject: [PATCH 144/327] Remove notice from Strassen Multiplication Matrix playground --- .../StrassensMatrixMultiplication.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift index 409e28c52..6b9314557 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation var A = Matrix(rows: 2, columns: 4, initialValue: 0) From 6ab163e4431ba09a6870b4b101dc536cffcf759d Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Fri, 5 Oct 2018 09:34:07 +0200 Subject: [PATCH 145/327] Update to Xcode 10. --- Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj | 6 +++++- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme | 4 +--- 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj b/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj index 84a305784..6df507720 100644 --- a/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -83,7 +83,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { @@ -145,12 +145,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -197,12 +199,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; diff --git a/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 538a6f4fa..afd69e6a7 100644 --- a/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 5 Oct 2018 09:49:56 +0200 Subject: [PATCH 146/327] Refactor to remove dependency on pre-Swift 4. The code used to depend on pre-Swift 4's optional operators, which have since been replaced. Now, the one possible case for comparing a potential `nil` maximum value has been handled. --- Bucket Sort/BucketSort.swift | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/Bucket Sort/BucketSort.swift b/Bucket Sort/BucketSort.swift index 108073288..4c2abd372 100644 --- a/Bucket Sort/BucketSort.swift +++ b/Bucket Sort/BucketSort.swift @@ -20,31 +20,6 @@ // // -import Foundation -// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. -// Consider refactoring the code to use the non-optional operators. -fileprivate func < (lhs: T?, rhs: T?) -> Bool { - switch (lhs, rhs) { - case let (l?, r?): - return l < r - case (nil, _?): - return true - default: - return false - } -} - -// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. -// Consider refactoring the code to use the non-optional operators. -fileprivate func >= (lhs: T?, rhs: T?) -> Bool { - switch (lhs, rhs) { - case let (l?, r?): - return l >= r - default: - return !(lhs < rhs) - } -} - ////////////////////////////////////// // MARK: Main algorithm ////////////////////////////////////// @@ -87,7 +62,11 @@ private func enoughSpaceInBuckets(_ buckets: [Bucket], elements: [T]) -> B let maximumValue = elements.max()?.toInt() let totalCapacity = buckets.count * (buckets.first?.capacity)! - return totalCapacity >= maximumValue + guard let max = maximumValue else { + return false + } + + return totalCapacity >= max } ////////////////////////////////////// From 8f2bf19304b379d60551359f913080e22b8d7ed3 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Fri, 5 Oct 2018 09:55:40 +0200 Subject: [PATCH 147/327] Change playground as well. --- .../Sources/BucketSort.swift | 31 +++---------------- .../contents.xcplayground | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ 3 files changed, 14 insertions(+), 27 deletions(-) create mode 100644 Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift b/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift index bafd216fa..64408eca4 100644 --- a/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift +++ b/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift @@ -20,31 +20,6 @@ // // -import Foundation -// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. -// Consider refactoring the code to use the non-optional operators. -fileprivate func < (lhs: T?, rhs: T?) -> Bool { - switch (lhs, rhs) { - case let (l?, r?): - return l < r - case (nil, _?): - return true - default: - return false - } -} - -// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. -// Consider refactoring the code to use the non-optional operators. -fileprivate func >= (lhs: T?, rhs: T?) -> Bool { - switch (lhs, rhs) { - case let (l?, r?): - return l >= r - default: - return !(lhs < rhs) - } -} - ////////////////////////////////////// // MARK: Main algorithm ////////////////////////////////////// @@ -87,7 +62,11 @@ private func enoughSpaceInBuckets(_ buckets: [Bucket], elements: [T]) -> B let maximumValue = elements.max()?.toInt() let totalCapacity = buckets.count * (buckets.first?.capacity)! - return totalCapacity >= maximumValue + guard let max = maximumValue else { + return false + } + + return totalCapacity >= max } ////////////////////////////////////// diff --git a/Bucket Sort/BucketSort.playground/contents.xcplayground b/Bucket Sort/BucketSort.playground/contents.xcplayground index 5da2641c9..9f5f2f40c 100644 --- a/Bucket Sort/BucketSort.playground/contents.xcplayground +++ b/Bucket Sort/BucketSort.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From f28973201916ac83c3b95f4115215a09715d22b7 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Fri, 5 Oct 2018 09:58:24 +0200 Subject: [PATCH 148/327] Add credit to README. --- Bucket Sort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bucket Sort/README.markdown b/Bucket Sort/README.markdown index f572fc9a1..f2708d71e 100644 --- a/Bucket Sort/README.markdown +++ b/Bucket Sort/README.markdown @@ -256,4 +256,4 @@ The following are some of the variation to the general [Bucket Sort](https://en. - [Postman Sort](https://en.wikipedia.org/wiki/Bucket_sort#Postman.27s_sort) - [Shuffle Sort](https://en.wikipedia.org/wiki/Bucket_sort#Shuffle_sort) -*Written for Swift Algorithm Club by Barbara Rodeker. Images from Wikipedia.* +*Written for Swift Algorithm Club by Barbara Rodeker. Images from Wikipedia. Updated by Bruno Scheele.* From 184786db68a17e40cfe2e4de6f7f212a84db42d4 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Fri, 5 Oct 2018 21:27:02 -0400 Subject: [PATCH 149/327] [Swift 4.2] Threaded Binary Tree --- .../ThreadedBinaryTree.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift b/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift index 4ce9d8157..ece1966e0 100644 --- a/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // Simple little debug function to make testing output pretty func check(_ tree: ThreadedBinaryTree?) { if let tree = tree { diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From cafba43a1c38bad9f62400e42ef46b9f51c60df3 Mon Sep 17 00:00:00 2001 From: Aleph Retamal Date: Sat, 6 Oct 2018 18:11:50 +1000 Subject: [PATCH 150/327] [Swift 4.2] Update K-Means --- K-Means/KMeans.swift | 2 +- K-Means/Tests/KMeansTests.swift | 7 ------ K-Means/Tests/Tests.xcodeproj/project.pbxproj | 24 +++++++++++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 5 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 K-Means/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/K-Means/KMeans.swift b/K-Means/KMeans.swift index 4a89a3fae..bccc6efd3 100644 --- a/K-Means/KMeans.swift +++ b/K-Means/KMeans.swift @@ -12,7 +12,7 @@ class KMeans { } private func indexOfNearestCenter(_ x: Vector, centers: [Vector]) -> Int { - var nearestDist = DBL_MAX + var nearestDist = Double.greatestFiniteMagnitude var minIndex = 0 for (idx, center) in centers.enumerated() { diff --git a/K-Means/Tests/KMeansTests.swift b/K-Means/Tests/KMeansTests.swift index e6f4b08a1..7e0c93004 100644 --- a/K-Means/Tests/KMeansTests.swift +++ b/K-Means/Tests/KMeansTests.swift @@ -10,13 +10,6 @@ import Foundation import XCTest class KMeansTests: XCTestCase { - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } - func genPoints(_ numPoints: Int, numDimensions: Int) -> [Vector] { var points = [Vector]() for _ in 0.. + + + + IDEDidComputeMac32BitWarning + + + diff --git a/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 2b401e86e..73ba8f37d 100644 --- a/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Sat, 6 Oct 2018 19:28:22 +1000 Subject: [PATCH 151/327] [Swift 4.2] Update Egg Drop Problem --- Egg Drop Problem/EggDrop.playground/Contents.swift | 4 ---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/WorkspaceSettings.xcsettings | 5 +++++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/Egg Drop Problem/EggDrop.playground/Contents.swift b/Egg Drop Problem/EggDrop.playground/Contents.swift index 0b707da98..decaacdca 100644 --- a/Egg Drop Problem/EggDrop.playground/Contents.swift +++ b/Egg Drop Problem/EggDrop.playground/Contents.swift @@ -1,7 +1,3 @@ -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - drop(numberOfEggs: 2, numberOfFloors: 2) //expected answer: 2 drop(numberOfEggs: 2, numberOfFloors: 4) //expected answer: 3 drop(numberOfEggs: 2, numberOfFloors: 6) //expected answer: 3 diff --git a/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..0c67376eb --- /dev/null +++ b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + From 2d60bb78c249085c47714474d27d97297a09fa2f Mon Sep 17 00:00:00 2001 From: askari01 Date: Sat, 6 Oct 2018 23:02:19 +0500 Subject: [PATCH 152/327] 2 sum problem with swift 4.2 --- Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift | 5 +---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift | 5 +---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 4 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift b/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift index 26bfae449..00a39b04a 100644 --- a/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift +++ b/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift @@ -1,8 +1,5 @@ //: Two Sum -// Last checked with: Version 9.0 (9A235) -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +// Last checked with: Version 10.0 (10A255) func twoSum(_ nums: [Int], target: Int) -> (Int, Int)? { var dict = [Int: Int]() diff --git a/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift b/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift index 4cb3d9283..469c15b5f 100644 --- a/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift +++ b/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift @@ -1,8 +1,5 @@ //: Playground - noun: a place where people can play -// Last checked with: Version 9.0 beta 4 (9M189t) -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +// Last checked with: Version 10.0 (10A255) func twoSumProblem(_ a: [Int], k: Int) -> ((Int, Int))? { var i = 0 diff --git a/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From f0ce485316036d977470c7d38e9a1959e8a60f08 Mon Sep 17 00:00:00 2001 From: askari01 Date: Sat, 6 Oct 2018 23:08:23 +0500 Subject: [PATCH 153/327] updated readme for 2 sum problem with swift 4.2 --- Two-Sum Problem/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Two-Sum Problem/README.markdown b/Two-Sum Problem/README.markdown index 4d8ffcd95..bbd033343 100644 --- a/Two-Sum Problem/README.markdown +++ b/Two-Sum Problem/README.markdown @@ -168,4 +168,4 @@ I'm quite enamored by this little algorithm. It shows that with some basic prepr * [3Sum / 4Sum](https://github.com/raywenderlich/swift-algorithm-club/tree/master/3Sum%20and%204Sum) -*Written for Swift Algorithm Club by Matthijs Hollemans and Daniel Speiser* +*Written for Swift Algorithm Club by Matthijs Hollemans and Daniel Speiser updated to swift 4.2 by Farrukh Askari* From 86d6cd114d34a602f987ab0f7a7b21d1ff7580ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Gra=C3=A7a?= Date: Mon, 8 Oct 2018 19:06:01 +1100 Subject: [PATCH 154/327] [Swift 4.2] Update Karatsuba multiplication Changed the way the characters in a String were accessed since `characters` was deprecated on Swift 4.0. Removed the code snippet at the beggining of the file. --- .../Contents.swift | 17 +++++++---------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../KaratsubaMultiplication.swift | 12 ++++++------ 3 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift index 04aff1ec4..e0ce23b19 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift @@ -1,10 +1,7 @@ //: Playground - noun: a place where people can play import Foundation -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4") -#endif + precedencegroup ExponentiativePrecedence { higherThan: MultiplicationPrecedence lowerThan: BitwiseShiftPrecedence @@ -18,8 +15,8 @@ func ^^ (radix: Int, power: Int) -> Int { // Long Multiplication - O(n^2) func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { - let num1Array = String(num1).characters.reversed().map { Int(String($0))! } - let num2Array = String(num2).characters.reversed().map { Int(String($0))! } + let num1Array = String(num1).reversed().map { Int(String($0))! } + let num2Array = String(num2).reversed().map { Int(String($0))! } var product = Array(repeating: 0, count: num1Array.count + num2Array.count) @@ -38,14 +35,14 @@ func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { // Karatsuba Multiplication - O(n^log2(3)) func karatsuba(_ num1: Int, by num2: Int) -> Int { - let num1Array = String(num1).characters - let num2Array = String(num2).characters + let num1String = String(num1) + let num2String = String(num2) - guard num1Array.count > 1 && num2Array.count > 1 else { + guard num1String.count > 1 && num2String.count > 1 else { return multiply(num1, by: num2) } - let n = max(num1Array.count, num2Array.count) + let n = max(num1String.count, num2String.count) let nBy2 = n / 2 let a = num1 / 10^^nBy2 diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.swift b/Karatsuba Multiplication/KaratsubaMultiplication.swift index fb20a667d..a82e82658 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.swift @@ -20,14 +20,14 @@ func ^^ (radix: Int, power: Int) -> Int { } func karatsuba(_ num1: Int, by num2: Int) -> Int { - let num1Array = String(num1).characters - let num2Array = String(num2).characters + let num1String = String(num1) + let num2String = String(num2) - guard num1Array.count > 1 && num2Array.count > 1 else { - return num1 * num2 + guard num1String.count > 1 && num2String.count > 1 else { + return multiply(num1, by: num2) } - - let n = max(num1Array.count, num2Array.count) + + let n = max(num1String.count, num2String.count) let nBy2 = n / 2 let a = num1 / 10^^nBy2 From ab20d205384c4fc40908f99dcfb941d485cac3c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Gra=C3=A7a?= Date: Mon, 8 Oct 2018 19:22:09 +1100 Subject: [PATCH 155/327] [Swift 4.2] Update README.md for Karatsuba multiplication --- Karatsuba Multiplication/README.markdown | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown index c86f69831..3a48ed39d 100644 --- a/Karatsuba Multiplication/README.markdown +++ b/Karatsuba Multiplication/README.markdown @@ -71,15 +71,15 @@ Here's the full implementation. Note that the recursive algorithm is most effici ```swift // Karatsuba Multiplication -func karatsuba(_ num1: Int, by num2: Int) -> Int { - let num1Array = String(num1).characters - let num2Array = String(num2).characters + func karatsuba(_ num1: Int, by num2: Int) -> Int { + let num1String = String(num1) + let num2String = String(num2) - guard num1Array.count > 1 && num2Array.count > 1 else { - return num1*num2 + guard num1String.count > 1 && num2String.count > 1 else { + return multiply(num1, by: num2) } - let n = max(num1Array.count, num2Array.count) + let n = max(num1String.count, num2String.count) let nBy2 = n / 2 let a = num1 / 10^^nBy2 From 2d1d22316401f52ac6a08325c781e812e40542c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Gra=C3=A7a?= Date: Mon, 8 Oct 2018 20:20:30 +1100 Subject: [PATCH 156/327] [Swift 4.2] added tests --- .travis.yml | 1 + .../KaratsubaMultiplication.swift | 31 +- .../Tests/KaratsubaMultiplicationTests.swift | 17 + .../Tests/Tests.xcodeproj/project.pbxproj | 305 ++++++++++++++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 56 ++++ .../Tests/Tests/Info.plist | 22 ++ .../contents.xcworkspacedata | 7 + 7 files changed, 434 insertions(+), 5 deletions(-) create mode 100644 Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift create mode 100644 Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme create mode 100644 Karatsuba Multiplication/Tests/Tests/Info.plist diff --git a/.travis.yml b/.travis.yml index edf1cf89f..56e205656 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,6 +48,7 @@ script: - xcodebuild test -project ./Treap/Treap/Treap.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` - xcodebuild test -project ./Palindromes/Test/Test.xcodeproj -scheme Test | xcpretty -f `xcpretty-travis-formatter` - xcodebuild test -project ./Ternary\ Search\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Karatsuba\ Multiplication/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` after_success: diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.swift b/Karatsuba Multiplication/KaratsubaMultiplication.swift index a82e82658..3d14a243a 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.swift @@ -19,27 +19,48 @@ func ^^ (radix: Int, power: Int) -> Int { return Int(pow(Double(radix), Double(power))) } +// Long Multiplication - O(n^2) +func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { + let num1Array = String(num1).reversed().map { Int(String($0))! } + let num2Array = String(num2).reversed().map { Int(String($0))! } + + var product = Array(repeating: 0, count: num1Array.count + num2Array.count) + + for i in num1Array.indices { + var carry = 0 + for j in num2Array.indices { + product[i + j] += carry + num1Array[i] * num2Array[j] + carry = product[i + j] / base + product[i + j] %= base + } + product[i + num2Array.count] += carry + } + + return Int(product.reversed().map { String($0) }.reduce("", +))! +} + +// Karatsuba Multiplication - O(n^log2(3)) func karatsuba(_ num1: Int, by num2: Int) -> Int { let num1String = String(num1) let num2String = String(num2) - + guard num1String.count > 1 && num2String.count > 1 else { return multiply(num1, by: num2) } let n = max(num1String.count, num2String.count) let nBy2 = n / 2 - + let a = num1 / 10^^nBy2 let b = num1 % 10^^nBy2 let c = num2 / 10^^nBy2 let d = num2 % 10^^nBy2 - + let ac = karatsuba(a, by: c) let bd = karatsuba(b, by: d) let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd - + let product = ac * 10^^(2 * nBy2) + adPlusbc * 10^^nBy2 + bd - + return product } diff --git a/Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift b/Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift new file mode 100644 index 000000000..379c9e812 --- /dev/null +++ b/Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift @@ -0,0 +1,17 @@ +// +// KaratsubaMultiplicationTests.swift +// Tests +// +// Created by Afonso Graça on 8/10/18. +// + +import XCTest + +final class KaratsubaMultiplicationTests: XCTestCase { + + func testReadmeExample() { + let subject = karatsuba(1234, by: 5678) + + XCTAssertEqual(subject, 7006652) + } +} diff --git a/Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj b/Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..ef23067ee --- /dev/null +++ b/Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,305 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 6AF099AC216B54E200F69B16 /* KaratsubaMultiplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AF099AB216B54E200F69B16 /* KaratsubaMultiplication.swift */; }; + 6AF099AE216B55A100F69B16 /* KaratsubaMultiplicationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AF099AD216B55A100F69B16 /* KaratsubaMultiplicationTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 6AF099A2216B54D500F69B16 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 6AF099A7216B54D500F69B16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; + 6AF099AB216B54E200F69B16 /* KaratsubaMultiplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = KaratsubaMultiplication.swift; path = ../KaratsubaMultiplication.swift; sourceTree = ""; }; + 6AF099AD216B55A100F69B16 /* KaratsubaMultiplicationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KaratsubaMultiplicationTests.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 6AF0999F216B54D500F69B16 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 6AF09997216B545D00F69B16 = { + isa = PBXGroup; + children = ( + 6AF099AB216B54E200F69B16 /* KaratsubaMultiplication.swift */, + 6AF099A4216B54D500F69B16 /* Tests */, + 6AF099A3216B54D500F69B16 /* Products */, + ); + sourceTree = ""; + }; + 6AF099A3216B54D500F69B16 /* Products */ = { + isa = PBXGroup; + children = ( + 6AF099A2216B54D500F69B16 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 6AF099A4216B54D500F69B16 /* Tests */ = { + isa = PBXGroup; + children = ( + 6AF099AD216B55A100F69B16 /* KaratsubaMultiplicationTests.swift */, + 6AF099A7216B54D500F69B16 /* Info.plist */, + ); + name = Tests; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6AF099A1216B54D500F69B16 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6AF099A8216B54D500F69B16 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 6AF0999E216B54D500F69B16 /* Sources */, + 6AF0999F216B54D500F69B16 /* Frameworks */, + 6AF099A0216B54D500F69B16 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 6AF099A2216B54D500F69B16 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 6AF09998216B545D00F69B16 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1000; + LastUpgradeCheck = 1000; + TargetAttributes = { + 6AF099A1216B54D500F69B16 = { + CreatedOnToolsVersion = 10.0; + }; + }; + }; + buildConfigurationList = 6AF0999B216B545D00F69B16 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 6AF09997216B545D00F69B16; + productRefGroup = 6AF099A3216B54D500F69B16 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 6AF099A1216B54D500F69B16 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 6AF099A0216B54D500F69B16 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 6AF0999E216B54D500F69B16 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6AF099AE216B55A100F69B16 /* KaratsubaMultiplicationTests.swift in Sources */, + 6AF099AC216B54E200F69B16 /* KaratsubaMultiplication.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 6AF0999C216B545D00F69B16 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Debug; + }; + 6AF0999D216B545D00F69B16 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Release; + }; + 6AF099A9216B54D500F69B16 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + 6AF099AA216B54D500F69B16 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 4.2; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 6AF0999B216B545D00F69B16 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6AF0999C216B545D00F69B16 /* Debug */, + 6AF0999D216B545D00F69B16 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6AF099A8216B54D500F69B16 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6AF099A9216B54D500F69B16 /* Debug */, + 6AF099AA216B54D500F69B16 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 6AF09998216B545D00F69B16 /* Project object */; +} diff --git a/Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..1288fd9a8 --- /dev/null +++ b/Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Karatsuba Multiplication/Tests/Tests/Info.plist b/Karatsuba Multiplication/Tests/Tests/Info.plist new file mode 100644 index 000000000..6c40a6cd0 --- /dev/null +++ b/Karatsuba Multiplication/Tests/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 142713e62..9305ae37c 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1472,6 +1472,13 @@ + + + + Date: Mon, 8 Oct 2018 20:31:20 +1100 Subject: [PATCH 157/327] [Swift 4.2] Update Fizz Buzz There was no need to update the source code, simply removed the code snippet. --- Fizz Buzz/FizzBuzz.playground/Contents.swift | 5 +---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Fizz Buzz/FizzBuzz.playground/Contents.swift b/Fizz Buzz/FizzBuzz.playground/Contents.swift index 37acdab61..ae966bbcc 100644 --- a/Fizz Buzz/FizzBuzz.playground/Contents.swift +++ b/Fizz Buzz/FizzBuzz.playground/Contents.swift @@ -1,7 +1,4 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +// last checked with Xcode 10.0 (10A255) func fizzBuzz(_ numberOfTurns: Int) { for i in 1...numberOfTurns { diff --git a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 409e85fdc8968230758ef703804f51956dc524a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B0=D0=BD=D0=BA=D0=BE=D0=B2=D0=B0=20=D0=9C=D0=B0?= =?UTF-8?q?=D1=80=D0=B8=D1=8F=20=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D1=8C=D0=B5?= =?UTF-8?q?=D0=B2=D0=BD=D0=B0?= Date: Mon, 8 Oct 2018 21:49:03 +0700 Subject: [PATCH 158/327] [Swift 4.2] Update Convex Hull --- .../Convex Hull.xcodeproj/project.pbxproj | 26 +++++++++++++++---- .../xcshareddata/xcschemes/Tests.xcscheme | 4 +-- .../AppIcon.appiconset/Contents.json | 5 ++++ Convex Hull/Convex Hull/View.swift | 4 +-- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Convex Hull/Convex Hull.xcodeproj/project.pbxproj b/Convex Hull/Convex Hull.xcodeproj/project.pbxproj index c11cbf4d6..27ca4eb25 100644 --- a/Convex Hull/Convex Hull.xcodeproj/project.pbxproj +++ b/Convex Hull/Convex Hull.xcodeproj/project.pbxproj @@ -139,7 +139,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0900; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = Workmoose; TargetAttributes = { 1CB6142C1F89456C00A14493 = { @@ -254,7 +254,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mnespor.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Convex Hull.app/Convex Hull"; }; @@ -281,7 +281,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mnespor.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Convex Hull.app/Convex Hull"; }; @@ -296,15 +296,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -346,15 +354,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -389,7 +405,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "workmoose.Convex-Hull"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -402,7 +418,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "workmoose.Convex-Hull"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 1f93a0c4f..8f04a0f51 100644 --- a/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 8 Oct 2018 19:30:25 -0300 Subject: [PATCH 159/327] removed duplicate implementation --- .../MyPlayground.playground/Contents.swift | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Bubble Sort/MyPlayground.playground/Contents.swift b/Bubble Sort/MyPlayground.playground/Contents.swift index 16466e0bc..8d27d801e 100644 --- a/Bubble Sort/MyPlayground.playground/Contents.swift +++ b/Bubble Sort/MyPlayground.playground/Contents.swift @@ -1,22 +1,5 @@ import Foundation -public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { - var array = elements - - for i in 0.. Date: Mon, 8 Oct 2018 19:30:58 -0300 Subject: [PATCH 160/327] changed tab width to 2 spaces instead of 4 --- .../Sources/BubbleSort.swift | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift index 5ce18ef9b..9c091b661 100644 --- a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift +++ b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift @@ -26,17 +26,17 @@ import Foundation /// - Parameter elements: the array to be sorted /// - Returns: an array with the same elements but in order public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { - var array = elements - - for i in 0.. Date: Mon, 8 Oct 2018 20:16:55 -0300 Subject: [PATCH 161/327] updated readme to conform with changes requested --- Bubble Sort/README.markdown | 75 +++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index 80161ce56..e55129d93 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -1,6 +1,6 @@ # Bubble Sort -Bubble sort is a sorting algorithm that is implemented by starting in the beginning of the array and swapping the first two elements only if the first element is greater than the second element. This comparison is then moved onto the next pair and so on and so forth. This is done until the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array.Sometimes this algorithm is refered as Sinking sort, due to the larger, or heavier elements sinking to the end of the array. +Bubble sort is a sorting algorithm that is implemented by starting in the beginning of the array and swapping the first two elements only if the first element is greater than the second element. This comparison is then moved onto the next pair and so on and so forth. This is done until the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array. Sometimes this algorithm is refered as Sinking sort, due to the larger, or heavier elements sinking to the end of the array. ##### Runtime: - Average: O(N^2) @@ -16,6 +16,10 @@ The implementation will not be shown as the average and worst runtimes show that Bubble sort is a very simple sorting algorithm, it consists in comparing pairs of adjacent elements in the array, if the first element is larger, swap them, otherwise, you do nothing and go for the next comparison. This is accomplished by looking through the array `n` times, `n` being the amount of elements in the array. +![animated gif of the bubble sort algorithm](https://s3.amazonaws.com/codecademy-content/programs/tdd-js/articles/BubbleSort.gif) + +This GIF shows a inverted implementation than + #### Example Let us take the array `[5, 1, 4, 2, 8]`, and sort the array from lowest number to greatest number using bubble sort. In each step, elements written in bold are being compared. Three passes will be required. @@ -52,13 +56,13 @@ This is the same for the forth and fifth passes. #### Code ```swift for i in 0.. [ **1 5** 4 2 8 ], Swaps since 5 > 1 + +[ 1 **5 4** 2 8 ] -> [ 1 **4 5** 2 8 ], Swap since 5 > 4 + +[ 1 4 **5 2** 8 ] -> [ 1 4 **2 5** 8 ], Swap since 5 > 2 + +[ 1 4 2 **5 8** ] -> [ 1 4 2 **5 8** ], Now, since these elements are already in order (8 > 5), algorithm does not swap them. + +*by the end of the first pass, the last element is guaranteed to be the largest* + +##### Second Pass +[ **1 4** 2 5 8 ] -> [ **1 4** 2 5 8 ] + +[ 1 **4 2** 5 8 ] -> [ 1 **2 4** 5 8 ], Swap since 4 > 2 + +[ 1 2 **4 5** 8 ] -> [ 1 2 **4 5** 8 ], As the first loop has occured once, the inner loop stops here, not comparing 5 with 8 + +##### Third Pass +[ **1 2** 4 5 8 ] -> [ **1 2** 4 5 8 ] + +[ 1 **2 4** 5 8 ] -> [ 1 **2 4** 5 8 ] again, stoping one comparison short + +##### Fourth Pass +[ **1 2** 4 5 8 ] -> [ **1 2** 4 5 8 ] + +There is no Fifth pass + +#### Conclusion + +Even with the proposed optimizations, this is still a terribly inefficient sorting algorithm. A good alternative is [Merge Sort](), that not only is better performing, has a similar degree of dificulty to implement. + +*Updated for the Swift Algorithm Club by Julio Brazil* + +##### Supporting Links +[Code Pumpkin](https://codepumpkin.com/bubble-sort/) +[Wikipedia](https://en.wikipedia.org/wiki/Bubble_sort) +[GeeksforGeeks](https://www.geeksforgeeks.org/bubble-sort/) From 39971b49661a7179117511ddfc6c79e1bde12378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=BA=D0=B0=D1=82=D0=B5=D1=80=D0=B8=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=91=D0=B0=D1=82=D0=B5=D0=B5=D0=B2=D0=B0?= Date: Wed, 10 Oct 2018 22:39:38 +0300 Subject: [PATCH 162/327] [Swift 4.2] Update Boyer-Moore-Horspool --- .../BoyerMooreHorspool.playground/Contents.swift | 6 +++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../BoyerMooreHorspool.playground/timeline.xctimeline | 6 +++--- Boyer-Moore-Horspool/BoyerMooreHorspool.swift | 6 +++--- 4 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift index e88a1b93d..5817cc41f 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -16,13 +16,13 @@ extension String { func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline index 89bc76f90..2688d72c1 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift index af8aea9d9..dbd738740 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift @@ -9,13 +9,13 @@ extension String { func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } From 8e6c983cd0c5ae26a68531bb54521b85f3926120 Mon Sep 17 00:00:00 2001 From: Varun Date: Thu, 11 Oct 2018 13:41:40 +0530 Subject: [PATCH 163/327] updated LinkedList.playground to swift 4.2 --- Linked List/LinkedList.playground/Contents.swift | 4 ---- Linked List/LinkedList.playground/contents.xcplayground | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index cfa3a8b45..894b2d37f 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -3,10 +3,6 @@ // For best results, don't forget to select "Show Rendered Markup" from XCode's "Editor" menu //: Linked List Class Declaration: -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif public final class LinkedList { diff --git a/Linked List/LinkedList.playground/contents.xcplayground b/Linked List/LinkedList.playground/contents.xcplayground index 3de2b51ba..5e28f2dd0 100644 --- a/Linked List/LinkedList.playground/contents.xcplayground +++ b/Linked List/LinkedList.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From 3f0ee826265621d22205316a3f52f22d7e5ee39f Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 11 Oct 2018 14:17:34 +0200 Subject: [PATCH 164/327] Update to Swift 4.2. Also removed unused Tests group from project. --- .../project.pbxproj | 22 ++++++++----------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++++ 2 files changed, 17 insertions(+), 13 deletions(-) create mode 100644 DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj index ecb060026..97f3c4847 100755 --- a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj @@ -27,13 +27,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - OBJ_10 /* Tests */ = { - isa = PBXGroup; - children = ( - ); - path = Tests; - sourceTree = ""; - }; OBJ_11 /* Products */ = { isa = PBXGroup; children = ( @@ -42,15 +35,13 @@ name = Products; sourceTree = BUILT_PRODUCTS_DIR; }; - OBJ_5 /* */ = { + OBJ_5 = { isa = PBXGroup; children = ( OBJ_6 /* Package.swift */, OBJ_7 /* Sources */, - OBJ_10 /* Tests */, OBJ_11 /* Products */, ); - name = ""; sourceTree = ""; }; OBJ_7 /* Sources */ = { @@ -96,6 +87,11 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 9999; + TargetAttributes = { + OBJ_13 = { + LastSwiftMigration = 1000; + }; + }; }; buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "DiningPhilosophers" */; compatibilityVersion = "Xcode 3.2"; @@ -104,7 +100,7 @@ knownRegions = ( en, ); - mainGroup = OBJ_5 /* */; + mainGroup = OBJ_5; productRefGroup = OBJ_11 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -139,7 +135,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; SWIFT_FORCE_DYNAMIC_LINK_STDLIB = YES; SWIFT_FORCE_STATIC_LINK_STDLIB = NO; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGET_NAME = DiningPhilosophers; }; name = Debug; @@ -157,7 +153,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; SWIFT_FORCE_DYNAMIC_LINK_STDLIB = YES; SWIFT_FORCE_STATIC_LINK_STDLIB = NO; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGET_NAME = DiningPhilosophers; }; name = Release; diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 6c48b3d493b4e6f023b006871f58fbe485db96b1 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 11 Oct 2018 14:18:45 +0200 Subject: [PATCH 165/327] Add README.md to project. This makes it easier to read along with the code. --- DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj index 97f3c4847..7699219de 100755 --- a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 232D7939216F76F700831A74 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; OBJ_12 /* DiningPhilosophers */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = DiningPhilosophers; sourceTree = BUILT_PRODUCTS_DIR; }; OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; OBJ_9 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; @@ -38,6 +39,7 @@ OBJ_5 = { isa = PBXGroup; children = ( + 232D7939216F76F700831A74 /* README.md */, OBJ_6 /* Package.swift */, OBJ_7 /* Sources */, OBJ_11 /* Products */, From f2c04f7ac0ed2634221eca58ed303e3a3b239cd9 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 11 Oct 2018 14:18:54 +0200 Subject: [PATCH 166/327] Add credit to README.md. --- DiningPhilosophers/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index cd9d86154..aed9dfe59 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -57,3 +57,4 @@ A background DispatchQueue is then used to let any Philosopher run asyncrounosly Dining Philosophers on Wikipedia https://en.wikipedia.org/wiki/Dining_philosophers_problem Written for Swift Algorithm Club by Jacopo Mangiavacchi +Swift 4.2 check by Bruno Scheele From eeb116e4073a0b1a0a9d13701bbe27d29e1ec6bb Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 11 Oct 2018 14:26:17 +0200 Subject: [PATCH 167/327] Update to Swift 4.2. --- Red-Black Tree/RedBlackTree.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Red-Black Tree/RedBlackTree.playground/Contents.swift b/Red-Black Tree/RedBlackTree.playground/Contents.swift index f14f18e58..d1133bc98 100644 --- a/Red-Black Tree/RedBlackTree.playground/Contents.swift +++ b/Red-Black Tree/RedBlackTree.playground/Contents.swift @@ -2,11 +2,6 @@ // Test for the RedBlackTree implementation provided in the Source folder of this Playground import Foundation -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let redBlackTree = RedBlackTree() let randomMax = Double(0x10000000) diff --git a/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From af9a6564f87da3390d9c0287995ba213f47c94ad Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 11 Oct 2018 14:26:34 +0200 Subject: [PATCH 168/327] Add credit to README.md. --- Red-Black Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Red-Black Tree/README.markdown b/Red-Black Tree/README.markdown index 74fffa415..fd6c4db18 100644 --- a/Red-Black Tree/README.markdown +++ b/Red-Black Tree/README.markdown @@ -186,4 +186,4 @@ The overall runtime of delete is O(log n). ## Resources: [CLRS] T. Cormen, C. Leiserson, R. Rivest, and C. Stein. "Introduction to Algorithms", Third Edition. 2009 -*Written for Swift Algorithm Club by Ute Schiehlen. Updated from Jaap Wijnen and Ashwin Raghuraman's contributions.* +*Written for Swift Algorithm Club by Ute Schiehlen. Updated from Jaap Wijnen and Ashwin Raghuraman's contributions. Swift 4.2 check by Bruno Scheele.* From d3d382f1d2f76c91a14a9b61b02375f7c6388265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=BA=D0=B0=D1=82=D0=B5=D1=80=D0=B8=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=91=D0=B0=D1=82=D0=B5=D0=B5=D0=B2=D0=B0?= Date: Fri, 12 Oct 2018 23:06:22 +0300 Subject: [PATCH 169/327] Fix HarversineDistance pi parameter in "Converts from degrees to radians" --- HaversineDistance/HaversineDistance.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HaversineDistance/HaversineDistance.playground/Contents.swift b/HaversineDistance/HaversineDistance.playground/Contents.swift index 5b3f591d6..7aa686645 100644 --- a/HaversineDistance/HaversineDistance.playground/Contents.swift +++ b/HaversineDistance/HaversineDistance.playground/Contents.swift @@ -16,7 +16,7 @@ func haversineDinstance(la1: Double, lo1: Double, la2: Double, lo2: Double, radi // Converts from degrees to radians let dToR = { (angle: Double) -> Double in - return (angle / 360) * 2 * M_PI + return (angle / 360) * 2 * .pi } let lat1 = dToR(la1) From acb21c32df8cc6c2ba8c153497902c24a661fff4 Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Fri, 12 Oct 2018 17:18:55 -0400 Subject: [PATCH 170/327] Updated MST to Swift 4.2 --- .../MinimumSpanningTree.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift b/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift index c4f0a811b..7e3532429 100644 --- a/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift @@ -3,11 +3,6 @@ Kruskal's and Prim's algorithms. */ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - func minimumSpanningTreeKruskal(graph: Graph) -> (cost: Int, tree: Graph) { var cost: Int = 0 var tree = Graph() diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From e0c6676601b6de0b093d3a171bf7497c73947522 Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Fri, 12 Oct 2018 17:37:17 -0400 Subject: [PATCH 171/327] Updated MST (Unweighted) to Swift 4.2 --- .../Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift index 65aa9fbc4..8ad04379c 100644 --- a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - func breadthFirstSearchMinimumSpanningTree(_ graph: Graph, source: Node) -> Graph { let minimumSpanningTree = graph.duplicate() diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 45cca894960b5aab35f8e675c1e2066025e7df91 Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Fri, 12 Oct 2018 17:40:24 -0400 Subject: [PATCH 172/327] Updated MST (Unweighted) tests to Swift 4.2 --- .../Tests/Tests.xcodeproj/project.pbxproj | 31 ++++++++++++++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj index a066b7a71..afb3b8acb 100644 --- a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj @@ -89,12 +89,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0820; + LastSwiftMigration = 1000; }; }; }; @@ -149,13 +149,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,13 +203,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -218,6 +238,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; @@ -231,7 +252,8 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -244,7 +266,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..afd69e6a7 100644 --- a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Sat, 13 Oct 2018 10:59:37 +0300 Subject: [PATCH 173/327] update Huffman Coding to Swift 4.2 --- Huffman Coding/Huffman.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Huffman Coding/Huffman.playground/Contents.swift b/Huffman Coding/Huffman.playground/Contents.swift index 6242ad272..2d59908e9 100644 --- a/Huffman Coding/Huffman.playground/Contents.swift +++ b/Huffman Coding/Huffman.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation let s1 = "so much words wow many compression" From 85738885f0ec2e2f6041eb8545a4cfa99233e783 Mon Sep 17 00:00:00 2001 From: Viktor Sokolov Date: Sat, 13 Oct 2018 11:21:15 +0300 Subject: [PATCH 174/327] Update Quad Tree to Swift 4.2 --- QuadTree/QuadTree.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/QuadTree/QuadTree.playground/Contents.swift b/QuadTree/QuadTree.playground/Contents.swift index f0d8cb2ef..ad8ee31f8 100644 --- a/QuadTree/QuadTree.playground/Contents.swift +++ b/QuadTree/QuadTree.playground/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b5 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation let tree = QuadTree(rect: Rect(origin: Point(0, 0), size: Size(xLength: 10, yLength: 10))) From 61400ea88862429ea588cf07e396377ca485d9b0 Mon Sep 17 00:00:00 2001 From: Viktor Sokolov Date: Sat, 13 Oct 2018 11:31:57 +0300 Subject: [PATCH 175/327] Update Multiset to Swift 4.2 --- Multiset/Multiset.playground/Contents.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Multiset/Multiset.playground/Contents.swift b/Multiset/Multiset.playground/Contents.swift index b4f64ee1f..64b729df1 100644 --- a/Multiset/Multiset.playground/Contents.swift +++ b/Multiset/Multiset.playground/Contents.swift @@ -1,9 +1,5 @@ //: Playground - noun: a place where people can play -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - import Cocoa var set = Multiset() From bb9ae3b6629da9b837c4cf33f9dfd977b13a635d Mon Sep 17 00:00:00 2001 From: Viktor Sokolov Date: Sat, 13 Oct 2018 11:39:24 +0300 Subject: [PATCH 176/327] Update Monty Hall to Swift 4.2 --- Monty Hall Problem/MontyHall.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Monty Hall Problem/MontyHall.playground/Contents.swift b/Monty Hall Problem/MontyHall.playground/Contents.swift index 4bfff2340..a809410c7 100644 --- a/Monty Hall Problem/MontyHall.playground/Contents.swift +++ b/Monty Hall Problem/MontyHall.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - import Foundation func random(_ n: Int) -> Int { From 33a50920ebefc92ce844d6f024e8c4a49f2eb3ef Mon Sep 17 00:00:00 2001 From: Viktor Sokolov Date: Sat, 13 Oct 2018 11:49:26 +0300 Subject: [PATCH 177/327] Update Ring Buffer to Swift 4.2 --- Ring Buffer/RingBuffer.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Ring Buffer/RingBuffer.playground/Contents.swift b/Ring Buffer/RingBuffer.playground/Contents.swift index f9ddb9c99..adcf146b4 100644 --- a/Ring Buffer/RingBuffer.playground/Contents.swift +++ b/Ring Buffer/RingBuffer.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - public struct RingBuffer { fileprivate var array: [T?] fileprivate var readIndex = 0 From 2a2971800f986286b098928f0cce0199a749ba9e Mon Sep 17 00:00:00 2001 From: NORMANDY REAL Date: Sat, 13 Oct 2018 22:25:30 +0800 Subject: [PATCH 178/327] Migrate to Swift 4.2 --- Ordered Array/OrderedArray.playground/Contents.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Ordered Array/OrderedArray.playground/Contents.swift b/Ordered Array/OrderedArray.playground/Contents.swift index 5b6be6420..e48af22e2 100644 --- a/Ordered Array/OrderedArray.playground/Contents.swift +++ b/Ordered Array/OrderedArray.playground/Contents.swift @@ -1,9 +1,6 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif + public struct OrderedArray { fileprivate var array = [T]() From 58af4187be04c17586a3bb37f30fd269bffd2692 Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Sat, 13 Oct 2018 10:32:59 -0400 Subject: [PATCH 179/327] Updated LRU Cache to Swift 4.2 --- LRU Cache/LRUCache.playground/Contents.swift | 5 ----- .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/LRU Cache/LRUCache.playground/Contents.swift b/LRU Cache/LRUCache.playground/Contents.swift index 2ebc03242..35dcc5d59 100644 --- a/LRU Cache/LRUCache.playground/Contents.swift +++ b/LRU Cache/LRUCache.playground/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let cache = LRUCache(2) cache.set("a", val: 1) cache.set("b", val: 2) diff --git a/LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata b/LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 4130f3502c344e0b43f09c0ba6cef0221ef1ff92 Mon Sep 17 00:00:00 2001 From: karolms Date: Sun, 14 Oct 2018 01:37:22 -0300 Subject: [PATCH 180/327] Updated Bit Set to Swift 4.2 --- Bit Set/BitSet.playground/Contents.swift | 4 ---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index 95253ea27..568202a33 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -1,9 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif // Create a bit set that stores 140 bits var bits = BitSet(size: 140) diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From d4d5b473774e68a24d3320865749d3dfe257da88 Mon Sep 17 00:00:00 2001 From: karolms Date: Sun, 14 Oct 2018 01:51:54 -0300 Subject: [PATCH 181/327] Updated Kth largest element to Swift 4.2 --- Kth Largest Element/kthLargest.playground/Contents.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Kth Largest Element/kthLargest.playground/Contents.swift b/Kth Largest Element/kthLargest.playground/Contents.swift index e6fca2ceb..a27dfce7d 100644 --- a/Kth Largest Element/kthLargest.playground/Contents.swift +++ b/Kth Largest Element/kthLargest.playground/Contents.swift @@ -1,9 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif let a = [5, 1, 3, 2, 7, 6, 4] From 75182345961675c51823a5d8ec514d85e91c7de8 Mon Sep 17 00:00:00 2001 From: karolms Date: Sun, 14 Oct 2018 02:02:21 -0300 Subject: [PATCH 182/327] Revert "Updated Bit Set to Swift 4.2" This reverts commit 4130f3502c344e0b43f09c0ba6cef0221ef1ff92. --- Bit Set/BitSet.playground/Contents.swift | 4 ++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 -------- 2 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index 568202a33..95253ea27 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -1,5 +1,9 @@ //: Playground - noun: a place where people can play +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif // Create a bit set that stores 140 bits var bits = BitSet(size: 140) diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - From f7b3996dd301816a66618fc497edb546706e68d0 Mon Sep 17 00:00:00 2001 From: karolms Date: Sun, 14 Oct 2018 02:09:18 -0300 Subject: [PATCH 183/327] Updated Knuth-Morris-Pratt to Swift 4.2 --- .../KnuthMorrisPratt.playground/Contents.swift | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift index 6609c9abe..9b4a50fa0 100644 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift @@ -1,13 +1,8 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift4!") -#endif - func ZetaAlgorithm(ptnr: String) -> [Int]? { - let pattern = Array(ptnr.characters) + let pattern = Array(ptnr) let patternLength: Int = pattern.count guard patternLength > 0 else { @@ -65,7 +60,7 @@ extension String { func indexesOf(ptnr: String) -> [Int]? { - let text = Array(self.characters) + let text = Array(self) let pattern = Array(ptnr.characters) let textLength: Int = text.count From 6c2aa24b0674a97e755bf8c0acf480d6e107e756 Mon Sep 17 00:00:00 2001 From: karolms Date: Sun, 14 Oct 2018 02:23:51 -0300 Subject: [PATCH 184/327] Updated AVL Tree to Swift 4.2 --- AVL Tree/AVLTree.playground/Contents.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/AVL Tree/AVLTree.playground/Contents.swift b/AVL Tree/AVLTree.playground/Contents.swift index 04ef78d07..34c1e6ddd 100644 --- a/AVL Tree/AVLTree.playground/Contents.swift +++ b/AVL Tree/AVLTree.playground/Contents.swift @@ -1,9 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif let tree = AVLTree() From 6536cd7af049eec810033f9611e6e8e5767a8a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Gra=C3=A7a?= Date: Mon, 15 Oct 2018 13:17:08 +1100 Subject: [PATCH 185/327] fix indentation typos in the README.md --- Karatsuba Multiplication/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown index 3a48ed39d..aef0d744a 100644 --- a/Karatsuba Multiplication/README.markdown +++ b/Karatsuba Multiplication/README.markdown @@ -71,12 +71,12 @@ Here's the full implementation. Note that the recursive algorithm is most effici ```swift // Karatsuba Multiplication - func karatsuba(_ num1: Int, by num2: Int) -> Int { +func karatsuba(_ num1: Int, by num2: Int) -> Int { let num1String = String(num1) let num2String = String(num2) guard num1String.count > 1 && num2String.count > 1 else { - return multiply(num1, by: num2) + return multiply(num1, by: num2) } let n = max(num1String.count, num2String.count) From 32fe7e84c0378daacf3e4048cf2f4d55bdb22c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Gra=C3=A7a?= Date: Mon, 15 Oct 2018 13:25:42 +1100 Subject: [PATCH 186/327] [Swift 4.2] Update Miller-Rabin Primality Test References #748 There were no necessary code changes for Swift 4.2. Removed the snippet requested --- .../MRPrimality.playground/Contents.swift | 5 ----- .../playground.xcworkspace/contents.xcworkspacedata | 4 ++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift index d8fd7fad8..98032bd59 100644 --- a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // Real primes mrPrimalityTest(5) mrPrimalityTest(439) diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..94b2795e2 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,4 @@ + + + diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 75783274fd291f6f9e6e801734c1eefa3b77eb38 Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Tue, 16 Oct 2018 11:35:51 -0300 Subject: [PATCH 187/327] replaced repetitive implementation with call --- .../Sources/SelectionSort.swift | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift index 3a27ef9dd..e7c66481d 100644 --- a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift +++ b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift @@ -3,25 +3,7 @@ /// - Parameter array: array of elements that conform to the Comparable protocol /// - Returns: an array in ascending order public func selectionSort(_ array: [T]) -> [T] { - guard array.count > 1 else { return array } - - var a = array - for x in 0 ..< a.count - 1 { - - // Find the lowest value in the rest of the array. - var lowest = x - for y in x + 1 ..< a.count { - if a[y] < a[lowest] { - lowest = y - } - } - - // Swap the lowest value with the current array index. - if x != lowest { - a.swapAt(x, lowest) - } - } - return a + return insertionSort(array, <) } /// Performs the Selection sort algorithm on a array using the provided comparisson method From d321542c220e94607b056644c491c7436553103b Mon Sep 17 00:00:00 2001 From: Alex Persian Date: Tue, 16 Oct 2018 22:28:13 -0400 Subject: [PATCH 188/327] Changes class to enum and clarifies the reason why a copy is made --- Linked List/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linked List/README.markdown b/Linked List/README.markdown index 0c8431157..e81e00b9f 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -555,7 +555,7 @@ enum ListNode { } ``` -The big difference with the class-based version is that any modification you make to this list will result in a *new copy* being created. Whether that's what you want or not depends on the application. +The big difference with the enum-based version is that any modification you make to this list will result in a *new copy* being created because of [Swift's value semantics](https://developer.apple.com/swift/blog/?id=10). Whether that's what you want or not depends on the application. [I might fill out this section in more detail if there's a demand for it.] From f95093e7338bc66d73ff81b52f959ec0f4fdd2b5 Mon Sep 17 00:00:00 2001 From: Michael Pchelnikov Date: Thu, 18 Oct 2018 00:28:16 +0300 Subject: [PATCH 189/327] Update Sorted Set to Swift 4.2 --- .../Pages/Example 1.xcplaygroundpage/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift index 45af5f99d..c81f4d915 100644 --- a/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift +++ b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - //: # Example 1 with type Int var mySet = SortedSet() From 0c93543179946a42b44a11fb79061a6126a8d8b5 Mon Sep 17 00:00:00 2001 From: Erik Strottmann Date: Wed, 17 Oct 2018 22:01:48 -0700 Subject: [PATCH 190/327] Update Trie to Swift 4.2 Removes `#if swift(>=4.0)` checks and calls to deprecated `String.characters` property, and enables Xcode 10 recommended warnings. --- Trie/ReadMe.md | 4 +-- Trie/Trie/Trie.xcodeproj/project.pbxproj | 33 +++++++++++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ Trie/Trie/Trie/Trie.swift | 11 ++----- Trie/Trie/Trie/ViewController.swift | 5 --- Trie/Trie/TrieTests/TrieTests.swift | 5 --- 6 files changed, 39 insertions(+), 27 deletions(-) create mode 100644 Trie/Trie/Trie.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index 34b9beb9c..8e473a619 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -33,7 +33,7 @@ func contains(word: String) -> Bool { var currentNode = root // 2 - var characters = Array(word.lowercased().characters) + var characters = Array(word.lowercased()) var currentIndex = 0 // 3 @@ -74,7 +74,7 @@ func insert(word: String) { var currentNode = root // 2 - for character in word.lowercased().characters { + for character in word.lowercased() { // 3 if let childNode = currentNode.children[character] { currentNode = childNode diff --git a/Trie/Trie/Trie.xcodeproj/project.pbxproj b/Trie/Trie/Trie.xcodeproj/project.pbxproj index 90c5734cc..1e3602eea 100644 --- a/Trie/Trie/Trie.xcodeproj/project.pbxproj +++ b/Trie/Trie/Trie.xcodeproj/project.pbxproj @@ -195,20 +195,23 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Rick Zaccone"; TargetAttributes = { EB798DF91DFEF79900F0628D = { CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 1000; ProvisioningStyle = Automatic; }; EB798E0A1DFEF79900F0628D = { CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 1000; ProvisioningStyle = Automatic; TestTargetID = EB798DF91DFEF79900F0628D; }; EB798E151DFEF79900F0628D = { CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 1000; ProvisioningStyle = Automatic; TestTargetID = EB798DF91DFEF79900F0628D; }; @@ -326,15 +329,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -376,15 +387,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -418,7 +437,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.Trie; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -431,7 +450,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.Trie; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -445,7 +464,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.TrieTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Trie.app/Contents/MacOS/Trie"; }; name = Debug; @@ -460,7 +479,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.TrieTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Trie.app/Contents/MacOS/Trie"; }; name = Release; @@ -474,7 +493,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.TrieUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TEST_TARGET_NAME = Trie; }; name = Debug; @@ -488,7 +507,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.TrieUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TEST_TARGET_NAME = Trie; }; name = Release; diff --git a/Trie/Trie/Trie.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Trie/Trie/Trie.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Trie/Trie/Trie.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index 1a7017c4c..fbc933138 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -6,11 +6,6 @@ // Copyright © 2016 Rick Zaccone. All rights reserved. // -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - import Foundation /// A node in the trie @@ -105,7 +100,7 @@ extension Trie { return } var currentNode = root - for character in word.lowercased().characters { + for character in word.lowercased() { if let childNode = currentNode.children[character] { currentNode = childNode } else { @@ -130,7 +125,7 @@ extension Trie { return false } var currentNode = root - for character in word.lowercased().characters { + for character in word.lowercased() { guard let childNode = currentNode.children[character] else { return false } @@ -148,7 +143,7 @@ extension Trie { /// search failed. private func findLastNodeOf(word: String) -> Node? { var currentNode = root - for character in word.lowercased().characters { + for character in word.lowercased() { guard let childNode = currentNode.children[character] else { return nil } diff --git a/Trie/Trie/Trie/ViewController.swift b/Trie/Trie/Trie/ViewController.swift index 9c5e66163..928b01f4c 100644 --- a/Trie/Trie/Trie/ViewController.swift +++ b/Trie/Trie/Trie/ViewController.swift @@ -6,11 +6,6 @@ // Copyright © 2016 Rick Zaccone. All rights reserved. // -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - import Cocoa class ViewController: NSViewController { diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index 45be03aad..b69c5666e 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -6,11 +6,6 @@ // Copyright © 2016 Rick Zaccone. All rights reserved. // -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - import XCTest @testable import Trie From 5a200e0709ba32a7bd898336502264977b356f77 Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:25:37 +0200 Subject: [PATCH 191/327] renaming Palindromes to Palindrome also removing one implementation, moving the one on root level to the playground to reduce the number of implementations to maintain --- .../Sources/Palindrome.swift | 38 +++++++++++++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ .../Palindrome.swift} | 2 +- Palindromes/Test/Palindromes.swift | 26 ------------- .../Test/Test.xcodeproj/project.pbxproj | 16 +++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ 6 files changed, 65 insertions(+), 33 deletions(-) create mode 100644 Palindromes/Palindromes.playground/Sources/Palindrome.swift create mode 100644 Palindromes/Palindromes.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename Palindromes/{Palindromes.swift => Test/Palindrome.swift} (93%) delete mode 100644 Palindromes/Test/Palindromes.swift create mode 100644 Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Palindromes/Palindromes.playground/Sources/Palindrome.swift b/Palindromes/Palindromes.playground/Sources/Palindrome.swift new file mode 100644 index 000000000..a6d2274bf --- /dev/null +++ b/Palindromes/Palindromes.playground/Sources/Palindrome.swift @@ -0,0 +1,38 @@ +import Foundation + +/** + Validate that a string is a plaindrome + - parameter str: The string to validate + - returns: `true` if string is plaindrome, `false` if string is not + */ +func isPalindrome(_ str: String) -> Bool { + let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) + let length = strippedString.count + + if length > 1 { + return palindrome(strippedString.lowercased(), left: 0, right: length - 1) + } + return false +} + +/** + Compares a strings left side character against right side character following + - parameter str: The string to compare characters of + - parameter left: Index of left side to compare, must be less than or equal to right + - parameter right: Index of right side to compare, must be greater than or equal to left + - returns: `true` if left side and right side have all been compared and they all match, `false` if a left and right aren't equal + */ +private func palindrome(_ str: String, left: Int, right: Int) -> Bool { + if left >= right { + return true + } + + let lhs = str[str.index(str.startIndex, offsetBy: left)] + let rhs = str[str.index(str.startIndex, offsetBy: right)] + + if lhs != rhs { + return false + } + + return palindrome(str, left: left + 1, right: right - 1) +} diff --git a/Palindromes/Palindromes.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Palindromes/Palindromes.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Palindromes/Palindromes.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Palindromes/Palindromes.swift b/Palindromes/Test/Palindrome.swift similarity index 93% rename from Palindromes/Palindromes.swift rename to Palindromes/Test/Palindrome.swift index 9ddd04c80..16af14fdb 100644 --- a/Palindromes/Palindromes.swift +++ b/Palindromes/Test/Palindrome.swift @@ -2,7 +2,7 @@ import Foundation func isPalindrome(_ str: String) -> Bool { let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) - let length = strippedString.characters.count + let length = strippedString.count if length > 1 { return palindrome(strippedString.lowercased(), left: 0, right: length - 1) diff --git a/Palindromes/Test/Palindromes.swift b/Palindromes/Test/Palindromes.swift deleted file mode 100644 index 9ddd04c80..000000000 --- a/Palindromes/Test/Palindromes.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Foundation - -func isPalindrome(_ str: String) -> Bool { - let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) - let length = strippedString.characters.count - - if length > 1 { - return palindrome(strippedString.lowercased(), left: 0, right: length - 1) - } - return false -} - -private func palindrome(_ str: String, left: Int, right: Int) -> Bool { - if left >= right { - return true - } - - let lhs = str[str.index(str.startIndex, offsetBy: left)] - let rhs = str[str.index(str.startIndex, offsetBy: right)] - - if lhs != rhs { - return false - } - - return palindrome(str, left: left + 1, right: right - 1) -} diff --git a/Palindromes/Test/Test.xcodeproj/project.pbxproj b/Palindromes/Test/Test.xcodeproj/project.pbxproj index 07aae3e63..6af90d5c2 100644 --- a/Palindromes/Test/Test.xcodeproj/project.pbxproj +++ b/Palindromes/Test/Test.xcodeproj/project.pbxproj @@ -8,11 +8,11 @@ /* Begin PBXBuildFile section */ 9437D8841E0D960A00A38FB8 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9437D8831E0D960A00A38FB8 /* Test.swift */; }; - 9437D88B1E0D969500A38FB8 /* Palindromes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9437D8791E0D948A00A38FB8 /* Palindromes.swift */; }; + 9437D88B1E0D969500A38FB8 /* Palindrome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9437D8791E0D948A00A38FB8 /* Palindrome.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 9437D8791E0D948A00A38FB8 /* Palindromes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palindromes.swift; sourceTree = ""; }; + 9437D8791E0D948A00A38FB8 /* Palindrome.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palindrome.swift; sourceTree = ""; }; 9437D8811E0D960A00A38FB8 /* Test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Test.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 9437D8831E0D960A00A38FB8 /* Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; }; 9437D8851E0D960A00A38FB8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -32,7 +32,7 @@ 9437D8651E0D945200A38FB8 = { isa = PBXGroup; children = ( - 9437D8791E0D948A00A38FB8 /* Palindromes.swift */, + 9437D8791E0D948A00A38FB8 /* Palindrome.swift */, 9437D8821E0D960A00A38FB8 /* Test */, 9437D86F1E0D945200A38FB8 /* Products */, ); @@ -87,6 +87,7 @@ TargetAttributes = { 9437D8801E0D960A00A38FB8 = { CreatedOnToolsVersion = 8.2; + LastSwiftMigration = 1000; ProvisioningStyle = Automatic; }; }; @@ -123,7 +124,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 9437D88B1E0D969500A38FB8 /* Palindromes.swift in Sources */, + 9437D88B1E0D969500A38FB8 /* Palindrome.swift in Sources */, 9437D8841E0D960A00A38FB8 /* Test.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -229,7 +230,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -243,7 +245,8 @@ PRODUCT_BUNDLE_IDENTIFIER = self.edu.Test; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -266,6 +269,7 @@ 9437D8881E0D960A00A38FB8 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 73b0fc92b71fa5a40a8b6ddc6a664ede35d09858 Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:26:50 +0200 Subject: [PATCH 192/327] removing duplicate implementation --- .../Palindromes.playground/Contents.swift | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index 44662745a..ee43cce33 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -1,49 +1,7 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation -/** - Validate that a string is a plaindrome - - parameter str: The string to validate - - returns: `true` if string is plaindrome, `false` if string is not - */ -func isPalindrome(_ str: String) -> Bool { - let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) - let length = strippedString.characters.count - - if length > 1 { - return palindrome(strippedString.lowercased(), left: 0, right: length - 1) - } - return false -} - -/** - Compares a strings left side character against right side character following - - parameter str: The string to compare characters of - - parameter left: Index of left side to compare, must be less than or equal to right - - parameter right: Index of right side to compare, must be greater than or equal to left - - returns: `true` if left side and right side have all been compared and they all match, `false` if a left and right aren't equal - */ -private func palindrome(_ str: String, left: Int, right: Int) -> Bool { - if left >= right { - return true - } - - let lhs = str[str.index(str.startIndex, offsetBy: left)] - let rhs = str[str.index(str.startIndex, offsetBy: right)] - - if lhs != rhs { - return false - } - - return palindrome(str, left: left + 1, right: right - 1) -} - //true isPalindrome("A man, a plan, a canal, Panama!") isPalindrome("abbcbba") From 66509650d57cd11deeb081359cbc0e4f68877b8e Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:27:09 +0200 Subject: [PATCH 193/327] updating recommended project settings --- .../Test/Test.xcodeproj/project.pbxproj | 18 +++++++++++++++++- .../xcshareddata/xcschemes/Test.xcscheme | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Palindromes/Test/Test.xcodeproj/project.pbxproj b/Palindromes/Test/Test.xcodeproj/project.pbxproj index 6af90d5c2..8125d1f8d 100644 --- a/Palindromes/Test/Test.xcodeproj/project.pbxproj +++ b/Palindromes/Test/Test.xcodeproj/project.pbxproj @@ -82,7 +82,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0820; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Joshua Alvarado"; TargetAttributes = { 9437D8801E0D960A00A38FB8 = { @@ -141,15 +141,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -188,15 +196,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme b/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme index 9a1b39e69..72ae3d696 100644 --- a/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme +++ b/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 18 Oct 2018 09:28:36 +0200 Subject: [PATCH 194/327] setting SWIFT_SWIFT3_OBJC_INFERENCE to default --- Palindromes/Test/Test.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Palindromes/Test/Test.xcodeproj/project.pbxproj b/Palindromes/Test/Test.xcodeproj/project.pbxproj index 8125d1f8d..f01f6f061 100644 --- a/Palindromes/Test/Test.xcodeproj/project.pbxproj +++ b/Palindromes/Test/Test.xcodeproj/project.pbxproj @@ -246,7 +246,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.2; }; name = Debug; @@ -261,7 +261,7 @@ PRODUCT_BUNDLE_IDENTIFIER = self.edu.Test; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.2; }; name = Release; From d3acedfb063b65327d503a50e86dfbaeb545b90e Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:31:39 +0200 Subject: [PATCH 195/327] making isPalindrome(_:) public --- Palindromes/Palindromes.playground/Sources/Palindrome.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Palindromes/Palindromes.playground/Sources/Palindrome.swift b/Palindromes/Palindromes.playground/Sources/Palindrome.swift index a6d2274bf..3652dbb1f 100644 --- a/Palindromes/Palindromes.playground/Sources/Palindrome.swift +++ b/Palindromes/Palindromes.playground/Sources/Palindrome.swift @@ -5,7 +5,7 @@ import Foundation - parameter str: The string to validate - returns: `true` if string is plaindrome, `false` if string is not */ -func isPalindrome(_ str: String) -> Bool { +public func isPalindrome(_ str: String) -> Bool { let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) let length = strippedString.count From 5fe31fff9a5717815cb524b16eb3433fde20926b Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:31:42 +0200 Subject: [PATCH 196/327] cleanup --- Palindromes/Palindromes.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index ee43cce33..49f767982 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -2,7 +2,7 @@ import Foundation -//true +// true isPalindrome("A man, a plan, a canal, Panama!") isPalindrome("abbcbba") isPalindrome("racecar") From 93a4d2d24689ebc6beec1df55e28dc4e94318a96 Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:55:39 +0200 Subject: [PATCH 197/327] updating README --- Palindromes/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index 69520a132..e4012d8da 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -26,7 +26,7 @@ Here is a recursive implementation of this in Swift: ```swift func isPalindrome(_ str: String) -> Bool { let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) - let length = strippedString.characters.count + let length = strippedString.count if length > 1 { return palindrome(strippedString.lowercased(), left: 0, right: length - 1) From c4a89a24bee0269733f2ac8ed9605ae0f1574eaa Mon Sep 17 00:00:00 2001 From: Stefan Pleava Date: Thu, 18 Oct 2018 11:45:46 -0400 Subject: [PATCH 198/327] Update README.markdown I think it should say minimum not maximum in the description. --- Egg Drop Problem/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Egg Drop Problem/README.markdown b/Egg Drop Problem/README.markdown index b2f45d09e..416984193 100644 --- a/Egg Drop Problem/README.markdown +++ b/Egg Drop Problem/README.markdown @@ -12,7 +12,7 @@ If the object is incredibly resilient, and you may need to do the testing on the ## Description -You're in a building with **m** floors and you are given **n** eggs. What is the maximum number of attempts it will take to find out the floor that breaks the egg? +You're in a building with **m** floors and you are given **n** eggs. What is the minimum number of attempts it will take to find out the floor that breaks the egg? For convenience, here are a few rules to keep in mind: From 66d0b867e22378465d83aecce1c30609906538d5 Mon Sep 17 00:00:00 2001 From: Randy the Dev <37282011+RandyTheDev@users.noreply.github.com> Date: Mon, 22 Oct 2018 03:05:09 +1100 Subject: [PATCH 199/327] Updated Radix Sort to Swift 4.2 --- Radix Sort/RadixSort.playground/Contents.swift | 15 ++------------- .../RadixSort.playground/Sources/radixSort.swift | 1 - 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/Radix Sort/RadixSort.playground/Contents.swift b/Radix Sort/RadixSort.playground/Contents.swift index 941723c37..0b549fc9e 100644 --- a/Radix Sort/RadixSort.playground/Contents.swift +++ b/Radix Sort/RadixSort.playground/Contents.swift @@ -1,21 +1,10 @@ //: Playground - noun: a place where people can play -import Cocoa - -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // Test Radix Sort with small array of ten values var array: [Int] = [19, 4242, 2, 9, 912, 101, 55, 67, 89, 32] radixSort(&array) // Test Radix Sort with large array of 1000 random values -var bigArray = [Int](repeating: 0, count: 1000) -var i = 0 -while i < 1000 { - bigArray[i] = Int(arc4random_uniform(1000) + 1) - i += 1 -} +var bigArray = (0..<1000).map { _ in Int.random(in: 1...1000) } +bigArray radixSort(&bigArray) diff --git a/Radix Sort/RadixSort.playground/Sources/radixSort.swift b/Radix Sort/RadixSort.playground/Sources/radixSort.swift index 424d33fb9..af382f481 100644 --- a/Radix Sort/RadixSort.playground/Sources/radixSort.swift +++ b/Radix Sort/RadixSort.playground/Sources/radixSort.swift @@ -3,7 +3,6 @@ Sorting Algorithm that sorts an input array of integers digit by digit. */ -import Foundation // NOTE: This implementation does not handle negative numbers public func radixSort(_ array: inout [Int] ) { From 36ae366ea4faeb4bf96380df3d58ca4da34525c6 Mon Sep 17 00:00:00 2001 From: Randy the Dev <37282011+RandyTheDev@users.noreply.github.com> Date: Mon, 22 Oct 2018 04:01:21 +1100 Subject: [PATCH 200/327] Updated Radix Sort Tests to Swift 4.2 --- Radix Sort/Tests/RadixSortTests.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Radix Sort/Tests/RadixSortTests.swift b/Radix Sort/Tests/RadixSortTests.swift index 9b881318a..688bcdcb8 100644 --- a/Radix Sort/Tests/RadixSortTests.swift +++ b/Radix Sort/Tests/RadixSortTests.swift @@ -9,13 +9,6 @@ import XCTest class RadixSortTests: XCTestCase { - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } - func testCombSort() { let expectedSequence: [Int] = [2, 9, 19, 32, 55, 67, 89, 101, 912, 4242] var sequence = [19, 4242, 2, 9, 912, 101, 55, 67, 89, 32] From eab858255456bc4c3be0229cf852d91720ac3361 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Tue, 23 Oct 2018 18:08:08 +0530 Subject: [PATCH 201/327] [Swift 4.2] Updated Linear Search The code worked fine in Xcode 10. I removed code snippet at the top of playground file. --- Linear Search/LinearSearch.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Linear Search/LinearSearch.playground/Contents.swift b/Linear Search/LinearSearch.playground/Contents.swift index 8ac0e9a71..8c616ded4 100644 --- a/Linear Search/LinearSearch.playground/Contents.swift +++ b/Linear Search/LinearSearch.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - func linearSearch(_ array: [T], _ object: T) -> Int? { for (index, obj) in array.enumerated() where obj == object { return index From d4fdc7bfa84715fcae452439e874740fc6759d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20C=2E=20Kr=C3=BCger?= Date: Tue, 23 Oct 2018 15:32:33 +0200 Subject: [PATCH 202/327] Adds binary recursive stein algorithm to the GCD class * Improves the LCM by passing the used GCD algorithm into the function. * Find an easy GCD function if possible. --- GCD/GCD.playground/Contents.swift | 165 +++++++++++++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 + GCD/GCD.playground/timeline.xctimeline | 6 - GCD/GCD.swift | 141 ++++++++++++--- GCD/README.markdown | 68 ++++---- 5 files changed, 296 insertions(+), 92 deletions(-) create mode 100644 GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 GCD/GCD.playground/timeline.xctimeline diff --git a/GCD/GCD.playground/Contents.swift b/GCD/GCD.playground/Contents.swift index c44f28310..9dfd7cca9 100644 --- a/GCD/GCD.playground/Contents.swift +++ b/GCD/GCD.playground/Contents.swift @@ -1,39 +1,148 @@ //: Playground - noun: a place where people can play -// Recursive version -func gcd(_ a: Int, _ b: Int) -> Int { - let r = a % b - if r != 0 { - return gcd(b, r) - } else { +/* + Iterative approach based on the Euclidean algorithm. + The Euclidean algorithm is based on the principle that the greatest + common divisor of two numbers does not change if the larger number + is replaced by its difference with the smaller number. + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd if m and n + */ +func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { + var a: Int = 0 + var b: Int = max(m, n) + var r: Int = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } return b - } } /* -// Iterative version -func gcd(m: Int, _ n: Int) -> Int { - var a = 0 - var b = max(m, n) - var r = min(m, n) - - while r != 0 { - a = b - b = r - r = a % b - } - return b + Recursive approach based on the Euclidean algorithm. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n + - Note: The recursive version makes only tail recursive calls. + Most compilers for imperative languages do not optimize these. + The swift compiler as well as the obj-c compiler is able to do + optimizations for tail recursive calls, even though it still ends + up to be the same in terms of complexity. That said, tail call + elimination is not mutually exclusive to recursion. + */ +func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { + let r: Int = m % n + if r != 0 { + return gcdRecursiveEuklid(n, r) + } else { + return n + } +} + +/* + The binary GCD algorithm, also known as Stein's algorithm, + is an algorithm that computes the greatest common divisor of two + nonnegative integers. Stein's algorithm uses simpler arithmetic + operations than the conventional Euclidean algorithm; it replaces + division with arithmetic shifts, comparisons, and subtraction. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n + - Complexity: worst case O(n^2), where n is the number of bits + in the larger of the two numbers. Although each step reduces + at least one of the operands by at least a factor of 2, + the subtract and shift operations take linear time for very + large integers + */ +func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { + if let easySolution = findEasySolution(m, n) { return easySolution } + + if (m & 1) == 0 { + // m is even + if (n & 1) == 1 { + // and n is odd + return gcdBinaryRecursiveStein(m >> 1, n) + } else { + // both m and n are even + return gcdBinaryRecursiveStein(m >> 1, n >> 1) << 1 + } + } else if (n & 1) == 0 { + // m is odd, n is even + return gcdBinaryRecursiveStein(m, n >> 1) + } else if (m > n) { + // reduce larger argument + return gcdBinaryRecursiveStein((m - n) >> 1, n) + } else { + // reduce larger argument + return gcdBinaryRecursiveStein((n - m) >> 1, m) + } +} + +/* + Finds an easy solution for the gcd. + - Note: It might be relevant for different usecases to + try finding an easy solution for the GCD calculation + before even starting more difficult operations. + */ +func findEasySolution(_ m: Int, _ n: Int) -> Int? { + if m == n { + return m + } + if m == 0 { + return n + } + if n == 0 { + return m + } + return nil } -*/ -func lcm(_ m: Int, _ n: Int) -> Int { - return m / gcd(m, n) * n // we divide before multiplying to avoid integer overflow + +enum LCMError: Error { + case divisionByZero + case lcmEmptyList +} + +/* + Calculates the lcm for two given numbers using a specified gcd algorithm. + + - Parameter m: First natural number. + - Parameter n: Second natural number. + - Parameter using: The used gcd algorithm to calculate the lcm. + - Throws: Can throw a `divisionByZero` error if one of the given + attributes turns out to be zero or less. + - Returns: The least common multiplier of the two attributes as + an unsigned integer + */ +func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { + guard (m & n) != 0 else { throw LCMError.divisionByZero } + return m / gcdAlgorithm(m, n) * n } -gcd(52, 39) // 13 -gcd(228, 36) // 12 -gcd(51357, 3819) // 57 -gcd(841, 299) // 1 +gcdIterativeEuklid(52, 39) // 13 +gcdIterativeEuklid(228, 36) // 12 +gcdIterativeEuklid(51357, 3819) // 57 +gcdIterativeEuklid(841, 299) // 1 -lcm(2, 3) // 6 -lcm(10, 8) // 40 +gcdRecursiveEuklid(52, 39) // 13 +gcdRecursiveEuklid(228, 36) // 12 +gcdRecursiveEuklid(51357, 3819) // 57 +gcdRecursiveEuklid(841, 299) // 1 + +gcdBinaryRecursiveStein(52, 39) // 13 +gcdBinaryRecursiveStein(228, 36) // 12 +gcdBinaryRecursiveStein(51357, 3819) // 57 +gcdBinaryRecursiveStein(841, 299) // 1 + +do { + try lcm(2, 3, using: gcdIterativeEuklid) // 6 + try lcm(10, 8, using: gcdIterativeEuklid) // 40 +} catch { + dump(error) +} diff --git a/GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/GCD/GCD.playground/timeline.xctimeline b/GCD/GCD.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/GCD/GCD.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/GCD/GCD.swift b/GCD/GCD.swift index bd903e58a..85b7681f0 100644 --- a/GCD/GCD.swift +++ b/GCD/GCD.swift @@ -1,34 +1,125 @@ + /* - Euclid's algorithm for finding the greatest common divisor -*/ -func gcd(_ m: Int, _ n: Int) -> Int { - var a = 0 - var b = max(m, n) - var r = min(m, n) + Iterative approach based on the Euclidean algorithm. + The Euclidean algorithm is based on the principle that the greatest + common divisor of two numbers does not change if the larger number + is replaced by its difference with the smaller number. + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd if m and n + */ +func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { + var a: Int = 0 + var b: Int = max(m, n) + var r: Int = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } + return b +} - while r != 0 { - a = b - b = r - r = a % b - } - return b +/* + Recursive approach based on the Euclidean algorithm. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n + - Note: The recursive version makes only tail recursive calls. + Most compilers for imperative languages do not optimize these. + The swift compiler as well as the obj-c compiler is able to do + optimizations for tail recursive calls, even though it still ends + up to be the same in terms of complexity. That said, tail call + elimination is not mutually exclusive to recursion. + */ +func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { + let r: Int = m % n + if r != 0 { + return gcdRecursiveEuklid(n, r) + } else { + return n + } } /* -// Recursive version -func gcd(_ a: Int, _ b: Int) -> Int { - let r = a % b - if r != 0 { - return gcd(b, r) - } else { - return b - } + The binary GCD algorithm, also known as Stein's algorithm, + is an algorithm that computes the greatest common divisor of two + nonnegative integers. Stein's algorithm uses simpler arithmetic + operations than the conventional Euclidean algorithm; it replaces + division with arithmetic shifts, comparisons, and subtraction. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n + - Complexity: worst case O(n^2), where n is the number of bits + in the larger of the two numbers. Although each step reduces + at least one of the operands by at least a factor of 2, + the subtract and shift operations take linear time for very + large integers + */ +func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { + if let easySolution = findEasySolution(m, n) { return easySolution } + + if (m & 1) == 0 { + // m is even + if (n & 1) == 1 { + // and n is odd + return gcdBinaryRecursiveStein(m >> 1, n) + } else { + // both m and n are even + return gcdBinaryRecursiveStein(m >> 1, n >> 1) << 1 + } + } else if (n & 1) == 0 { + // m is odd, n is even + return gcdBinaryRecursiveStein(m, n >> 1) + } else if (m > n) { + // reduce larger argument + return gcdBinaryRecursiveStein((m - n) >> 1, n) + } else { + // reduce larger argument + return gcdBinaryRecursiveStein((n - m) >> 1, m) + } +} + +/* + Finds an easy solution for the gcd. + - Note: It might be relevant for different usecases to + try finding an easy solution for the GCD calculation + before even starting more difficult operations. + */ +func findEasySolution(_ m: Int, _ n: Int) -> Int? { + if m == n { + return m + } + if m == 0 { + return n + } + if n == 0 { + return m + } + return nil +} + + +enum LCMError: Error { + case divisionByZero + case lcmEmptyList } -*/ /* - Returns the least common multiple of two numbers. -*/ -func lcm(_ m: Int, _ n: Int) -> Int { - return m / gcd(m, n) * n + Calculates the lcm for two given numbers using a specified gcd algorithm. + + - Parameter m: First natural number. + - Parameter n: Second natural number. + - Parameter using: The used gcd algorithm to calculate the lcm. + - Throws: Can throw a `divisionByZero` error if one of the given + attributes turns out to be zero or less. + - Returns: The least common multiplier of the two attributes as + an unsigned integer + */ +func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { + guard (m & n) != 0 else { throw LCMError.divisionByZero } + return m / gcdAlgorithm(m, n) * n } diff --git a/GCD/README.markdown b/GCD/README.markdown index d7e9304bd..a23aea190 100644 --- a/GCD/README.markdown +++ b/GCD/README.markdown @@ -1,8 +1,8 @@ # Greatest Common Divisor -The *greatest common divisor* (or Greatest Common Factor) of two numbers `a` and `b` is the largest positive integer that divides both `a` and `b` without a remainder. +The *greatest common divisor* (or Greatest Common Factor) of two numbers `a` and `b` is the largest positive integer that divides both `a` and `b` without a remainder. The GCD.swift file contains three different algorithms of how to calculate the greatest common divisor. -For example, `gcd(39, 52) = 13` because 13 divides 39 (`39/13 = 3`) as well as 52 (`52/13 = 4`). But there is no larger number than 13 that divides them both. +For example, `gcdIterativeEuklid(39, 52) = 13` because 13 divides 39 (`39/13 = 3`) as well as 52 (`52/13 = 4`). But there is no larger number than 13 that divides them both. You've probably had to learn about this in school at some point. :-) @@ -17,25 +17,25 @@ where `a % b` calculates the remainder of `a` divided by `b`. Here is an implementation of this idea in Swift: ```swift -func gcd(_ a: Int, _ b: Int) -> Int { - let r = a % b - if r != 0 { - return gcd(b, r) - } else { - return b - } +func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { + let r: Int = m % n + if r != 0 { + return gcdRecursiveEuklid(n, r) + } else { + return n + } } ``` Put it in a playground and try it out with these examples: ```swift -gcd(52, 39) // 13 -gcd(228, 36) // 12 -gcd(51357, 3819) // 57 +gcdBinaryRecursiveStein(52, 39) // 13 +gcdRecursiveEuklid(228, 36) // 12 +gcdIterativeEuklid(51357, 3819) // 57 ``` -Let's step through the third example: +Let's step through the third example using gcd as a representation of the gcdRecursiveEuklid here: gcd(51357, 3819) @@ -47,10 +47,10 @@ because the remainder of `51357 % 3819` is `1710`. If you work out this division So `gcd(51357, 3819)` is the same as `gcd(3819, 1710)`. That's useful because we can keep simplifying: - gcd(3819, 1710) = gcd(1710, 3819 % 1710) = - gcd(1710, 399) = gcd(399, 1710 % 399) = - gcd(399, 114) = gcd(114, 399 % 114) = - gcd(114, 57) = gcd(57, 114 % 57) = + gcd(3819, 1710) = gcd(1710, 3819 % 1710) = + gcd(1710, 399) = gcd(399, 1710 % 399) = + gcd(399, 114) = gcd(114, 399 % 114) = + gcd(114, 57) = gcd(57, 114 % 57) = gcd(57, 0) And now can't divide any further. The remainder of `114 / 57` is zero because `114 = 57 * 2` exactly. That means we've found the answer: @@ -68,17 +68,17 @@ gcd(841, 299) // 1 Here is a slightly different implementation of Euclid's algorithm. Unlike the first version this doesn't use recursion but only a basic `while` loop. ```swift -func gcd(_ m: Int, _ n: Int) -> Int { - var a = 0 - var b = max(m, n) - var r = min(m, n) - - while r != 0 { - a = b - b = r - r = a % b - } - return b +func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { + var a: Int = 0 + var b: Int = max(m, n) + var r: Int = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } + return b } ``` @@ -88,9 +88,9 @@ The `max()` and `min()` at the top of the function make sure we always divide th An idea related to the GCD is the *least common multiple* or LCM. -The least common multiple of two numbers `a` and `b` is the smallest positive integer that is a multiple of both. In other words, the LCM is evenly divisible by `a` and `b`. +The least common multiple of two numbers `a` and `b` is the smallest positive integer that is a multiple of both. In other words, the LCM is evenly divisible by `a` and `b`. The example implementation of the LCM takes two numbers and a specification which GCD algorithm is used. -For example: `lcm(2, 3) = 6` because 6 can be divided by 2 and also by 3. +For example: `lcm(2, 3, using: gcdIterativeEuklid) = 6` because 6 can be divided by 2 and also by 3. We can calculate the LCM using Euclid's algorithm too: @@ -101,17 +101,19 @@ We can calculate the LCM using Euclid's algorithm too: In code: ```swift -func lcm(_ m: Int, _ n: Int) -> Int { - return m / gcd(m, n) * n +func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { + guard (m & n) != 0 else { throw LCMError.divisionByZero } + return m / gcdAlgorithm(m, n) * n } ``` And to try it out in a playground: ```swift -lcm(10, 8) // 40 +lcm(10, 8, using: gcdIterativeEuklid) // 40 ``` You probably won't need to use the GCD or LCM in any real-world problems, but it's cool to play around with this ancient algorithm. It was first described by Euclid in his [Elements](http://publicdomainreview.org/collections/the-first-six-books-of-the-elements-of-euclid-1847/) around 300 BC. Rumor has it that he discovered this algorithm while he was hacking on his Commodore 64. *Written for Swift Algorithm Club by Matthijs Hollemans* +*Extended by Simon Krüger* \ No newline at end of file From 0f08fa9ddb315a55cca92d1fbabecb48a406cee8 Mon Sep 17 00:00:00 2001 From: Rahul Date: Tue, 23 Oct 2018 19:02:39 +0530 Subject: [PATCH 203/327] [Swift 4.2] Updated Selection Sort --- Selection Sort/SelectionSort.playground/Contents.swift | 5 ----- .../SelectionSort.playground/Sources/SelectionSort.swift | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Selection Sort/SelectionSort.playground/Contents.swift b/Selection Sort/SelectionSort.playground/Contents.swift index b16dadb8d..a552c9edb 100644 --- a/Selection Sort/SelectionSort.playground/Contents.swift +++ b/Selection Sort/SelectionSort.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] selectionSort(list) selectionSort(list, <) diff --git a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift index e7c66481d..e157319b4 100644 --- a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift +++ b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift @@ -3,7 +3,7 @@ /// - Parameter array: array of elements that conform to the Comparable protocol /// - Returns: an array in ascending order public func selectionSort(_ array: [T]) -> [T] { - return insertionSort(array, <) + return selectionSort(array, <) } /// Performs the Selection sort algorithm on a array using the provided comparisson method From e0c8738b1f1a16184d79158df9b65c6d42fc1568 Mon Sep 17 00:00:00 2001 From: Rahul Date: Tue, 23 Oct 2018 19:21:46 +0530 Subject: [PATCH 204/327] [Swift 4.2] Updated Linked List --- Linked List/LinkedList.playground/Contents.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index cfa3a8b45..76b911310 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -3,10 +3,6 @@ // For best results, don't forget to select "Show Rendered Markup" from XCode's "Editor" menu //: Linked List Class Declaration: -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif public final class LinkedList { @@ -459,7 +455,7 @@ var sum = 0 for element in collection { sum += element } -// sum is 15 +sum //15 // Another way of achieving the same result though 'reduce', another method defined in an extension of Sequence. Collections are Sequences. let result = collection.reduce(0) {$0 + $1} // 15 From 71b20f41f8e1926a3c4f10a8fc3eca05d98ab193 Mon Sep 17 00:00:00 2001 From: laurentaylormarshall Date: Tue, 23 Oct 2018 22:25:10 -0500 Subject: [PATCH 205/327] Removes Swift 4.0 checks and updates the Swift version to 4.2. --- Comb Sort/Comb Sort.playground/Contents.swift | 6 +---- Comb Sort/Tests/CombSortTests.swift | 1 + .../Tests/Tests.xcodeproj/project.pbxproj | 22 ++++++++++++++++--- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Comb Sort/Comb Sort.playground/Contents.swift b/Comb Sort/Comb Sort.playground/Contents.swift index 39e24248a..1f7723838 100644 --- a/Comb Sort/Comb Sort.playground/Contents.swift +++ b/Comb Sort/Comb Sort.playground/Contents.swift @@ -2,11 +2,7 @@ // Created by Stephen Rutstein // 7-16-2016 -import Cocoa -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +import Foundation // Test Comb Sort with small array of ten values let array = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] diff --git a/Comb Sort/Tests/CombSortTests.swift b/Comb Sort/Tests/CombSortTests.swift index e972c0a57..783fbd150 100644 --- a/Comb Sort/Tests/CombSortTests.swift +++ b/Comb Sort/Tests/CombSortTests.swift @@ -17,6 +17,7 @@ class CombSortTests: XCTestCase { print("Hello, Swift 4!") #endif } + override func setUp() { super.setUp() sequence = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] diff --git a/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj index 7530acbdc..14d059271 100644 --- a/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -82,7 +82,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0820; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 056E92741E2483D300B30F52 = { @@ -142,15 +142,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -192,15 +200,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -235,7 +251,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "Swift-Algorithm-Club.Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -248,7 +264,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "Swift-Algorithm-Club.Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 55e697ad3..48faa2df7 100644 --- a/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Tue, 23 Oct 2018 22:40:49 -0500 Subject: [PATCH 206/327] Updates tests to check for Swift 4.2. Updates build settings to use Swift 4.2. --- Comb Sort/Tests/CombSortTests.swift | 6 +++--- Comb Sort/Tests/Tests.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Comb Sort/Tests/CombSortTests.swift b/Comb Sort/Tests/CombSortTests.swift index 783fbd150..166065484 100644 --- a/Comb Sort/Tests/CombSortTests.swift +++ b/Comb Sort/Tests/CombSortTests.swift @@ -12,9 +12,9 @@ class CombSortTests: XCTestCase { var sequence: [Int]! let expectedSequence: [Int] = [-12, -10, -1, 2, 9, 32, 55, 67, 89, 101] - func testSwift4(){ - #if swift(>=4.0) - print("Hello, Swift 4!") + func testSwiftVersion(){ + #if swift(>=4.2) + print("Hello, Swift 4.2!") #endif } diff --git a/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj index 14d059271..4582b3f2d 100644 --- a/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -187,7 +187,7 @@ SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -237,7 +237,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; From 8da637c1d1c92cc65ea3eeb63275dc6117432b67 Mon Sep 17 00:00:00 2001 From: laurentaylormarshall Date: Tue, 23 Oct 2018 23:32:46 -0500 Subject: [PATCH 207/327] Removes Swift 4.0 check. Removes unused import. Refactors an if statement into a guard to be more Swift-y. --- Slow Sort/SlowSort.playground/Contents.swift | 5 ----- Slow Sort/SlowSort.swift | 7 ++----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Slow Sort/SlowSort.playground/Contents.swift b/Slow Sort/SlowSort.playground/Contents.swift index 95bf80739..7c686782c 100644 --- a/Slow Sort/SlowSort.playground/Contents.swift +++ b/Slow Sort/SlowSort.playground/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - var numberList = [1, 12, 9, 17, 13, 12] slowsort(0, numberList.count-1, &numberList) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index 9f264a057..c68a53455 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -6,12 +6,9 @@ // // -import Foundation - public func slowsort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - if i>=j { - return - } + guard i Date: Tue, 23 Oct 2018 23:41:43 -0500 Subject: [PATCH 208/327] Removes Swift 4.0 check. Removes unused import. Refactors an if statement into a guard to be more Swift-y. Removes unnecessarily explicitly defining the function as public. --- Slow Sort/SlowSort.playground/Contents.swift | 7 +------ Slow Sort/SlowSort.swift | 8 ++------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Slow Sort/SlowSort.playground/Contents.swift b/Slow Sort/SlowSort.playground/Contents.swift index 95bf80739..54c1e61ea 100644 --- a/Slow Sort/SlowSort.playground/Contents.swift +++ b/Slow Sort/SlowSort.playground/Contents.swift @@ -1,9 +1,4 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - var numberList = [1, 12, 9, 17, 13, 12] -slowsort(0, numberList.count-1, &numberList) +slowSort(0, numberList.count-1, &numberList) print(numberList) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index 9f264a057..217733daa 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -6,12 +6,8 @@ // // -import Foundation - -public func slowsort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - if i>=j { - return - } +func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { + guard if i < j else { return } let m = (i+j)/2 slowsort(i, m, &numberList) slowsort(m+1, j, &numberList) From b5d5c89353857a26589d2e03bd72f442b45e1aa9 Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 12:17:59 +0200 Subject: [PATCH 209/327] Updated Binary Tree to Swift 4.2 --- Binary Tree/BinaryTree.playground/Contents.swift | 5 ----- Binary Tree/BinaryTree.playground/contents.xcplayground | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Binary Tree/BinaryTree.playground/Contents.swift b/Binary Tree/BinaryTree.playground/Contents.swift index 9da194fed..b0bff577a 100644 --- a/Binary Tree/BinaryTree.playground/Contents.swift +++ b/Binary Tree/BinaryTree.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - public indirect enum BinaryTree { case node(BinaryTree, T, BinaryTree) case empty diff --git a/Binary Tree/BinaryTree.playground/contents.xcplayground b/Binary Tree/BinaryTree.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Binary Tree/BinaryTree.playground/contents.xcplayground +++ b/Binary Tree/BinaryTree.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 016ae7c90bc525246f925480b6c6aa92eab47e4f Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 12:21:05 +0200 Subject: [PATCH 210/327] Update BitSet to Swift 4.2 --- Bit Set/BitSet.playground/Contents.swift | 5 ----- Bit Set/BitSet.playground/contents.xcplayground | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index 95253ea27..d11b36e8c 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // Create a bit set that stores 140 bits var bits = BitSet(size: 140) diff --git a/Bit Set/BitSet.playground/contents.xcplayground b/Bit Set/BitSet.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Bit Set/BitSet.playground/contents.xcplayground +++ b/Bit Set/BitSet.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 6d8e795377902dc7dbdc6ad0a2231f62ba3a0d49 Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 12:31:47 +0200 Subject: [PATCH 211/327] Update Bounded Priority Queue to Swift 4.2 --- .../BoundedPriorityQueue.playground/Contents.swift | 5 ----- .../BoundedPriorityQueue.playground/contents.xcplayground | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../Tests/Tests.xcodeproj/project.pbxproj | 6 +++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 5 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift b/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift index f8e219c13..d6204abec 100644 --- a/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - struct Message: Comparable, CustomStringConvertible { let name: String let priority: Int diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground b/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj index 842c51695..11f907b47 100644 --- a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -86,7 +86,7 @@ TargetAttributes = { B80004B21C83E342001FE2D7 = { CreatedOnToolsVersion = 7.2.1; - LastSwiftMigration = 0820; + LastSwiftMigration = 1000; }; }; }; @@ -226,7 +226,7 @@ SDKROOT = macosx; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -269,7 +269,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 57f25c429638b6a607d3e67f9e70f3633e2a1045 Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 13:16:15 +0200 Subject: [PATCH 212/327] Update Boyer Moore to Swift 4.2 --- .../BoyerMooreHorspool.playground/Contents.swift | 11 +++-------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Boyer-Moore-Horspool/BoyerMooreHorspool.swift | 6 +++--- Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift | 4 ++-- .../Tests/Tests.xcodeproj/project.pbxproj | 14 ++++++++------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 4 +--- .../contents.xcworkspacedata | 6 +++--- 8 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Boyer-Moore-Horspool/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift index e88a1b93d..1666549c1 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - /* Boyer-Moore string search @@ -16,13 +11,13 @@ extension String { func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift index af8aea9d9..dbd738740 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift @@ -9,13 +9,13 @@ extension String { func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } diff --git a/Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift b/Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift index 9efe60874..436173127 100755 --- a/Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift +++ b/Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift @@ -26,8 +26,8 @@ class BoyerMooreTest: XCTestCase { XCTAssertNotNil(index) let startIndex = index! - let endIndex = string.index(index!, offsetBy: pattern.characters.count) - let match = string.substring(with: startIndex.. + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 538a6f4fa..afd69e6a7 100644 --- a/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ + location = "group:Boyer-Moore-Horspool/BoyerMooreHorspool.playground"> + location = "group:Boyer-Moore-Horspool/BoyerMooreHorspool.swift"> From 7384ec29e4e95cbae0b6a93dc6ae2ffe66eecffb Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 13:20:32 +0200 Subject: [PATCH 213/327] Update Boyer Moore to Swift 4.2 --- .../contents.xcworkspacedata | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 04d4ac573..d85d538b3 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -609,19 +609,19 @@ + location = "group:BoyerMooreHorspool.playground"> + location = "group:BoyerMooreHorspool.swift"> @@ -633,7 +633,7 @@ location = "group:Info.plist"> + location = "group:/Users/mroedder/workspace/swift-algorithm-club/Boyer-Moore-Horspool/Tests/Tests.xcodeproj"> From 402f23669b3f5c06dbd64adfe885d873e3a23f65 Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 13:24:39 +0200 Subject: [PATCH 214/327] Update Boyer Moore to Swift 4.2 --- swift-algorithm-club.xcworkspace/contents.xcworkspacedata | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index d85d538b3..a37dac494 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -633,7 +633,7 @@ location = "group:Info.plist"> + location = "group:Tests/Tests.xcodeproj"> From 6ead6d0dcb0e77f51cbda0582a1b6f56c1d0ebd0 Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 13:27:09 +0200 Subject: [PATCH 215/327] Update README to use Swift 4.2 --- Boyer-Moore-Horspool/README.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Boyer-Moore-Horspool/README.markdown b/Boyer-Moore-Horspool/README.markdown index f5e21ea41..8879d8df6 100644 --- a/Boyer-Moore-Horspool/README.markdown +++ b/Boyer-Moore-Horspool/README.markdown @@ -38,13 +38,13 @@ extension String { func index(of pattern: String) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } @@ -162,13 +162,13 @@ extension String { func index(of pattern: String) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count + let patternLength = pattern.count guard patternLength > 0, patternLength <= characters.count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } From 13d152600da95a0864d14edae72c0d93c161781c Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 13:41:18 +0200 Subject: [PATCH 216/327] Update Breadth First Search to Swift 4.2 --- .../Contents.swift | 4 --- .../Sources/Graph.swift | 2 +- .../contents.xcplayground | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../Tests/Tests.xcodeproj/project.pbxproj | 30 +++++++++++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 7 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift index 3986a0cee..cf22ebb25 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift @@ -1,7 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif func breadthFirstSearch(_ graph: Graph, source: Node) -> [String] { var queue = Queue() diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift index 87e21897c..0343120f8 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift @@ -5,7 +5,7 @@ public class Graph: CustomStringConvertible, Equatable { self.nodes = [] } - public func addNode(_ label: String) -> Node { + @discardableResult public func addNode(_ label: String) -> Node { let node = Node(label) nodes.append(node) return node diff --git a/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground b/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground index 513c2e7e9..f635e9804 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground +++ b/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj index f86abf86e..a7f04e00a 100644 --- a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj +++ b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -59,7 +59,6 @@ 7B2BBC941C779E7B0067B71D /* Info.plist */, ); name = Tests; - path = TestsTests; sourceTree = ""; }; /* End PBXGroup section */ @@ -89,12 +88,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0820; + LastSwiftMigration = 1000; }; }; }; @@ -149,13 +148,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,13 +202,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -218,6 +237,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; @@ -231,7 +251,7 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -244,7 +264,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index dfcf6de42..afd69e6a7 100644 --- a/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 26 Oct 2018 14:33:49 +0200 Subject: [PATCH 217/327] Extended Miller-Rabin Primality test [code] * Adds a more readable documentation and clear naming for variables to the Miller-Rabin Primality Test example * Miller-Rabin can fail under certain situations. These have to throw an error. * Updates the relevant playground files * Add name to documentation --- .../MRPrimality.playground/Contents.swift | 46 ++--- .../Sources/MRPrimality.swift | 111 ------------ .../Sources/MillerRabin.swift | 100 +++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + Miller-Rabin Primality Test/MRPrimality.swift | 169 ++++++++---------- Miller-Rabin Primality Test/README.markdown | 5 +- 7 files changed, 221 insertions(+), 225 deletions(-) delete mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift index d8fd7fad8..1e4113c15 100644 --- a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift @@ -5,25 +5,27 @@ print("Hello, Swift 4!") #endif -// Real primes -mrPrimalityTest(5) -mrPrimalityTest(439) -mrPrimalityTest(1201) -mrPrimalityTest(143477) -mrPrimalityTest(1299869) -mrPrimalityTest(15487361) -mrPrimalityTest(179426363) -mrPrimalityTest(32416187747) - -// Fake primes -mrPrimalityTest(15) -mrPrimalityTest(435) -mrPrimalityTest(1207) -mrPrimalityTest(143473) -mrPrimalityTest(1291869) -mrPrimalityTest(15487161) -mrPrimalityTest(178426363) -mrPrimalityTest(32415187747) - -// With iteration -mrPrimalityTest(32416190071, iteration: 10) +do { + // Real primes + try checkWithMillerRabin(5) + try checkWithMillerRabin(439) + try checkWithMillerRabin(1201) + try checkWithMillerRabin(143477) + try checkWithMillerRabin(1299869) + try checkWithMillerRabin(15487361) + try checkWithMillerRabin(179426363) + + // Fake primes + try checkWithMillerRabin(15) + try checkWithMillerRabin(435) + try checkWithMillerRabin(1207) + try checkWithMillerRabin(143473) + try checkWithMillerRabin(1291869) + try checkWithMillerRabin(15487161) + try checkWithMillerRabin(178426363) + + // Specifying accuracy + try checkWithMillerRabin(179426363, accuracy: 10) +} catch { + dump(error) +} diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift deleted file mode 100644 index ee2ace8b9..000000000 --- a/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift +++ /dev/null @@ -1,111 +0,0 @@ -// -// MRPrimality.swift -// -// -// Created by Sahn Cha on 2016. 10. 18.. -// -// - -import Foundation - -/* - Miller-Rabin Primality Test. - One of the most used algorithms for primality testing. - Since this is a probabilistic algorithm, it needs to be executed multiple times to increase accuracy. - - Inputs: - n: UInt64 { target integer to be tested for primality } - k: Int { optional. number of iterations } - - Outputs: - true { probably prime } - false { composite } - */ -public func mrPrimalityTest(_ n: UInt64, iteration k: Int = 1) -> Bool { - guard n > 2 && n % 2 == 1 else { return false } - - var d = n - 1 - var s = 0 - - while d % 2 == 0 { - d /= 2 - s += 1 - } - - let range = UInt64.max - UInt64.max % (n - 2) - var r: UInt64 = 0 - repeat { - arc4random_buf(&r, MemoryLayout.size(ofValue: r)) - } while r >= range - - r = r % (n - 2) + 2 - - for _ in 1 ... k { - var x = powmod64(r, d, n) - if x == 1 || x == n - 1 { continue } - - if s == 1 { s = 2 } - - for _ in 1 ... s - 1 { - x = powmod64(x, 2, n) - if x == 1 { return false } - if x == n - 1 { break } - } - - if x != n - 1 { return false } - } - - return true -} - -/* - Calculates (base^exp) mod m. - - Inputs: - base: UInt64 { base } - exp: UInt64 { exponent } - m: UInt64 { modulus } - - Outputs: - the result - */ -private func powmod64(_ base: UInt64, _ exp: UInt64, _ m: UInt64) -> UInt64 { - if m == 1 { return 0 } - - var result: UInt64 = 1 - var b = base % m - var e = exp - - while e > 0 { - if e % 2 == 1 { result = mulmod64(result, b, m) } - b = mulmod64(b, b, m) - e >>= 1 - } - - return result -} - -/* - Calculates (first * second) mod m, hopefully without overflow. :] - - Inputs: - first: UInt64 { first integer } - second: UInt64 { second integer } - m: UInt64 { modulus } - - Outputs: - the result - */ -private func mulmod64(_ first: UInt64, _ second: UInt64, _ m: UInt64) -> UInt64 { - var result: UInt64 = 0 - var a = first - var b = second - - while a != 0 { - if a % 2 == 1 { result = ((result % m) + (b % m)) % m } // This may overflow if 'm' is a 64bit number && both 'result' and 'b' are very close to but smaller than 'm'. - a >>= 1 - b = (b << 1) % m - } - - return result -} diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift new file mode 100644 index 000000000..03daac1fa --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift @@ -0,0 +1,100 @@ +// +// MRPrimality.swift +// +// +// Created by Sahn Cha on 2016. 10. 18.. +// +// + +import Foundation + +enum MillerRabinError: Error { + case primeLowAccuracy + case primeLowerBorder + case uIntOverflow +} + +/* + The Miller–Rabin test relies on an equality or set of equalities that + hold true for prime values, then checks whether or not they hold for + a number that we want to test for primality. + + - Parameter n: an odd integer to be tested for primality; + - Parameter k: a parameter that determines the accuracy of the test + - throws: Can throw an error of type `MillerRabinError`. + - Returns: composite if n is composite, otherwise probably prime + */ +public func checkWithMillerRabin(_ n: UInt, accuracy k: UInt = 1) throws -> Bool { + guard k > 0 else { throw MillerRabinError.primeLowAccuracy } + guard n > 0 else { throw MillerRabinError.primeLowerBorder } + guard n > 3 else { return true } + + // return false for all even numbers bigger than 2 + if n % 2 == 0 { + return false + } + + let s: UInt = UInt((n - 1).trailingZeroBitCount) + let d: UInt = (n - 1) >> s + + guard UInt(pow(2.0, Double(s))) * d == n - 1 else { throw MillerRabinError.primeLowerBorder } + + /// Inspect whether a given witness will reveal the true identity of n. + func tryComposite(_ a: UInt, d: UInt, n: UInt) throws -> Bool? { + var x = try calculateModularExponentiation(base: a, exponent: d, modulus: n) + if x == 1 || x == (n - 1) { + return nil + } + for _ in 1.. UInt { + guard modulus > 1 else { return 0 } + guard !(modulus-1).multipliedReportingOverflow(by: (modulus-1)).overflow else { + throw MillerRabinError.uIntOverflow + } + + var result: UInt = 1 + var exponentCopy = exponent + var baseCopy = base % modulus + + while exponentCopy > 0 { + if exponentCopy % 2 == 1 { + result = (result * baseCopy) % modulus + } + exponentCopy = exponentCopy >> 1 + baseCopy = (baseCopy * baseCopy) % modulus + } + + return result +} diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Miller-Rabin Primality Test/MRPrimality.swift b/Miller-Rabin Primality Test/MRPrimality.swift index ee2ace8b9..24b9c674c 100644 --- a/Miller-Rabin Primality Test/MRPrimality.swift +++ b/Miller-Rabin Primality Test/MRPrimality.swift @@ -1,6 +1,6 @@ // // MRPrimality.swift -// +// // // Created by Sahn Cha on 2016. 10. 18.. // @@ -8,104 +8,93 @@ import Foundation -/* - Miller-Rabin Primality Test. - One of the most used algorithms for primality testing. - Since this is a probabilistic algorithm, it needs to be executed multiple times to increase accuracy. - - Inputs: - n: UInt64 { target integer to be tested for primality } - k: Int { optional. number of iterations } - - Outputs: - true { probably prime } - false { composite } - */ -public func mrPrimalityTest(_ n: UInt64, iteration k: Int = 1) -> Bool { - guard n > 2 && n % 2 == 1 else { return false } - - var d = n - 1 - var s = 0 - - while d % 2 == 0 { - d /= 2 - s += 1 - } - - let range = UInt64.max - UInt64.max % (n - 2) - var r: UInt64 = 0 - repeat { - arc4random_buf(&r, MemoryLayout.size(ofValue: r)) - } while r >= range - - r = r % (n - 2) + 2 - - for _ in 1 ... k { - var x = powmod64(r, d, n) - if x == 1 || x == n - 1 { continue } - - if s == 1 { s = 2 } - - for _ in 1 ... s - 1 { - x = powmod64(x, 2, n) - if x == 1 { return false } - if x == n - 1 { break } - } - - if x != n - 1 { return false } - } - - return true +enum MillerRabinError: Error { + case primeLowAccuracy + case primeLowerBorder + case uIntOverflow } /* - Calculates (base^exp) mod m. - - Inputs: - base: UInt64 { base } - exp: UInt64 { exponent } - m: UInt64 { modulus } - - Outputs: - the result - */ -private func powmod64(_ base: UInt64, _ exp: UInt64, _ m: UInt64) -> UInt64 { - if m == 1 { return 0 } + The Miller–Rabin test relies on an equality or set of equalities that + hold true for prime values, then checks whether or not they hold for + a number that we want to test for primality. + + - Parameter n: an odd integer to be tested for primality; + - Parameter k: a parameter that determines the accuracy of the test + - throws: Can throw an error of type `MillerRabinError`. + - Returns: composite if n is composite, otherwise probably prime +*/ +func checkWithMillerRabin(_ n: UInt, accuracy k: UInt = 1) throws -> Bool { + guard k > 0 else { throw MillerRabinError.primeLowAccuracy } + guard n > 0 else { throw MillerRabinError.primeLowerBorder } + guard n > 3 else { return true } + + // return false for all even numbers bigger than 2 + if n % 2 == 0 { + return false + } - var result: UInt64 = 1 - var b = base % m - var e = exp + let s: UInt = UInt((n - 1).trailingZeroBitCount) + let d: UInt = (n - 1) >> s + + guard UInt(pow(2.0, Double(s))) * d == n - 1 else { throw EncryptionError.primeLowerBorder } + + /// Inspect whether a given witness will reveal the true identity of n. + func tryComposite(_ a: UInt, d: UInt, n: UInt) throws -> Bool? { + var x = try calculateModularExponentiation(base: a, exponent: d, modulus: n) + if x == 1 || x == (n - 1) { + return nil + } + for _ in 1.. 0 { - if e % 2 == 1 { result = mulmod64(result, b, m) } - b = mulmod64(b, b, m) - e >>= 1 - } + for _ in 0.. UInt64 { - var result: UInt64 = 0 - var a = first - var b = second + Calculates the modular exponentiation based on `Applied Cryptography by Bruce Schneier.` + in `Schneier, Bruce (1996). Applied Cryptography: Protocols, Algorithms, + and Source Code in C, Second Edition (2nd ed.). Wiley. ISBN 978-0-471-11709-4.` + + - Parameter base: The natural base b. + - Parameter base: The natural exponent e. + - Parameter base: The natural modulus m. + - Throws: Can throw a `uIntOverflow` if the modulus' square exceeds the memory + limitations of UInt on the current system. + - Returns: The modular exponentiation c. +*/ +private func calculateModularExponentiation(base: UInt, exponent: UInt, modulus: UInt) throws -> UInt { + guard modulus > 1 else { return 0 } + guard !(modulus-1).multipliedReportingOverflow(by: (modulus-1)).overflow else { + throw MillerRabinError.uIntOverflow + } - while a != 0 { - if a % 2 == 1 { result = ((result % m) + (b % m)) % m } // This may overflow if 'm' is a 64bit number && both 'result' and 'b' are very close to but smaller than 'm'. - a >>= 1 - b = (b << 1) % m - } + var result: UInt = 1 + var exponentCopy = exponent + var baseCopy = base % modulus + + while exponentCopy > 0 { + if exponentCopy % 2 == 1 { + result = (result * baseCopy) % modulus + } + exponentCopy = exponentCopy >> 1 + baseCopy = (baseCopy * baseCopy) % modulus + } - return result + return result } diff --git a/Miller-Rabin Primality Test/README.markdown b/Miller-Rabin Primality Test/README.markdown index 07acb9e18..9cc677a2e 100644 --- a/Miller-Rabin Primality Test/README.markdown +++ b/Miller-Rabin Primality Test/README.markdown @@ -27,8 +27,8 @@ The following pseudo code is excerpted from Wikipedia[3]: ## Usage ```swift -mrPrimalityTest(7) // test if 7 is prime. (default iteration = 1) -mrPrimalityTest(7, iteration: 10) // test if 7 is prime && iterate 10 times. +checkWithMillerRabin(7) // test if 7 is prime. (default iteration = 1) +checkWithMillerRabin(7, accuracy: 10) // test if 7 is prime && iterate 10 times. ``` ## Reference @@ -37,6 +37,7 @@ mrPrimalityTest(7, iteration: 10) // test if 7 is prime && iterate 10 time 3. Miller–Rabin primality test - Wikipedia, the free encyclopedia _Written for Swift Algorithm Club by **Sahn Cha**, @scha00_ +_Code updated by **Simon C. Krüger**._ [1]: https://cs.uwaterloo.ca/research/tr/1975/CS-75-27.pdf [2]: http://www.sciencedirect.com/science/article/pii/0022314X80900840 From b47eb3e80afffc20c5e540e33fec66ae7a65bec0 Mon Sep 17 00:00:00 2001 From: laurentaylormarshall <44420971+laurentaylormarshall@users.noreply.github.com> Date: Fri, 26 Oct 2018 18:56:13 -0500 Subject: [PATCH 218/327] Update SlowSort.swift --- Slow Sort/SlowSort.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index c68a53455..813f3b7a9 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -5,10 +5,8 @@ // Created by Pope Lukas Schramm (Dabendorf Orthodox Religion) on 16-07-16. // // - -public func slowsort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - guard i Date: Fri, 26 Oct 2018 19:11:33 -0500 Subject: [PATCH 219/327] Updates function name. --- Slow Sort/SlowSort.swift | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index 813f3b7a9..3b762042a 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -1,19 +1,19 @@ // // SlowSort.swift -// +// // // Created by Pope Lukas Schramm (Dabendorf Orthodox Religion) on 16-07-16. // // func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - guard if i < j else { return } - let m = (i+j)/2 - slowsort(i, m, &numberList) - slowsort(m+1, j, &numberList) - if numberList[j] < numberList[m] { - let temp = numberList[j] - numberList[j] = numberList[m] - numberList[m] = temp - } - slowsort(i, j-1, &numberList) + guard if i < j else { return } + let m = (i+j)/2 + slowSort(i, m, &numberList) + slowSort(m+1, j, &numberList) + if numberList[j] < numberList[m] { + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp + } + slowSort(i, j-1, &numberList) } From 22efd0d33aa9d3bfacf3c84701dc157bb10e5aa7 Mon Sep 17 00:00:00 2001 From: Erik Strottmann Date: Sat, 27 Oct 2018 10:26:54 -0700 Subject: [PATCH 220/327] Standardize Trie indentation to 2 spaces 2 spaces is recommended by the Ray Wenderlich Swift Style Guide. --- Trie/ReadMe.md | 40 +-- Trie/Trie/Trie.xcodeproj/project.pbxproj | 2 + Trie/Trie/Trie/AppDelegate.swift | 12 +- Trie/Trie/Trie/Trie.swift | 118 ++++---- Trie/Trie/Trie/ViewController.swift | 16 +- Trie/Trie/TrieTests/TrieTests.swift | 340 +++++++++++------------ Trie/Trie/TrieUITests/TrieUITests.swift | 34 +-- 7 files changed, 280 insertions(+), 282 deletions(-) diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index 8e473a619..8d0c45c8a 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -27,29 +27,29 @@ Tries are very useful for certain situations. Here are some of the advantages: ```swift func contains(word: String) -> Bool { - guard !word.isEmpty else { return false } + guard !word.isEmpty else { return false } - // 1 - var currentNode = root + // 1 + var currentNode = root - // 2 - var characters = Array(word.lowercased()) - var currentIndex = 0 + // 2 + var characters = Array(word.lowercased()) + var currentIndex = 0 - // 3 - while currentIndex < characters.count, - let child = currentNode.children[characters[currentIndex]] { - - currentNode = child - currentIndex += 1 - } - - // 4 - if currentIndex == characters.count && currentNode.isTerminating { - return true - } else { - return false - } + // 3 + while currentIndex < characters.count, + let child = currentNode.children[characters[currentIndex]] { + + currentNode = child + currentIndex += 1 + } + + // 4 + if currentIndex == characters.count && currentNode.isTerminating { + return true + } else { + return false + } } ``` diff --git a/Trie/Trie/Trie.xcodeproj/project.pbxproj b/Trie/Trie/Trie.xcodeproj/project.pbxproj index 1e3602eea..6b7cc9b61 100644 --- a/Trie/Trie/Trie.xcodeproj/project.pbxproj +++ b/Trie/Trie/Trie.xcodeproj/project.pbxproj @@ -87,7 +87,9 @@ EB798E191DFEF79900F0628D /* TrieUITests */, EB798DFB1DFEF79900F0628D /* Products */, ); + indentWidth = 2; sourceTree = ""; + tabWidth = 2; }; EB798DFB1DFEF79900F0628D /* Products */ = { isa = PBXGroup; diff --git a/Trie/Trie/Trie/AppDelegate.swift b/Trie/Trie/Trie/AppDelegate.swift index b2c46695b..48dc24673 100644 --- a/Trie/Trie/Trie/AppDelegate.swift +++ b/Trie/Trie/Trie/AppDelegate.swift @@ -11,12 +11,12 @@ import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - func applicationDidFinishLaunching(_ aNotification: Notification) { - // Insert code here to initialize your application - } + func applicationDidFinishLaunching(_ aNotification: Notification) { + // Insert code here to initialize your application + } - func applicationWillTerminate(_ aNotification: Notification) { - // Insert code here to tear down your application - } + func applicationWillTerminate(_ aNotification: Notification) { + // Insert code here to tear down your application + } } diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index fbc933138..accc7b61c 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -43,54 +43,53 @@ class TrieNode { /// A trie data structure containing words. Each node is a single /// character of a word. class Trie: NSObject, NSCoding { - typealias Node = TrieNode - /// The number of words in the trie - public var count: Int { - return wordCount - } - /// Is the trie empty? - public var isEmpty: Bool { - return wordCount == 0 - } - /// All words currently in the trie - public var words: [String] { - return wordsInSubtrie(rootNode: root, partialWord: "") - } - fileprivate let root: Node - fileprivate var wordCount: Int - - /// Creates an empty trie. - override init() { - root = Node() - wordCount = 0 - super.init() - } + typealias Node = TrieNode + /// The number of words in the trie + public var count: Int { + return wordCount + } + /// Is the trie empty? + public var isEmpty: Bool { + return wordCount == 0 + } + /// All words currently in the trie + public var words: [String] { + return wordsInSubtrie(rootNode: root, partialWord: "") + } + fileprivate let root: Node + fileprivate var wordCount: Int + + /// Creates an empty trie. + override init() { + root = Node() + wordCount = 0 + super.init() + } - // MARK: NSCoding + // MARK: NSCoding - /// Initializes the trie with words from an archive - /// - /// - Parameter decoder: Decodes the archive - required convenience init?(coder decoder: NSCoder) { - self.init() - let words = decoder.decodeObject(forKey: "words") as? [String] - for word in words! { - self.insert(word: word) - } + /// Initializes the trie with words from an archive + /// + /// - Parameter decoder: Decodes the archive + required convenience init?(coder decoder: NSCoder) { + self.init() + let words = decoder.decodeObject(forKey: "words") as? [String] + for word in words! { + self.insert(word: word) } + } - /// Encodes the words in the trie by putting them in an array then encoding - /// the array. - /// - /// - Parameter coder: The object that will encode the array - func encode(with coder: NSCoder) { - coder.encode(self.words, forKey: "words") - } + /// Encodes the words in the trie by putting them in an array then encoding + /// the array. + /// + /// - Parameter coder: The object that will encode the array + func encode(with coder: NSCoder) { + coder.encode(self.words, forKey: "words") + } } // MARK: - Adds methods: insert, remove, contains extension Trie { - /// Inserts a word into the trie. If the word is already present, /// there is no change. /// @@ -142,14 +141,14 @@ extension Trie { /// - Returns: the node where the search ended, nil if the /// search failed. private func findLastNodeOf(word: String) -> Node? { - var currentNode = root - for character in word.lowercased() { - guard let childNode = currentNode.children[character] else { - return nil - } - currentNode = childNode + var currentNode = root + for character in word.lowercased() { + guard let childNode = currentNode.children[character] else { + return nil } - return currentNode + currentNode = childNode + } + return currentNode } /// Attempts to walk to the terminating node of a word. The @@ -160,10 +159,9 @@ extension Trie { /// search failed. private func findTerminalNodeOf(word: String) -> Node? { if let lastNode = findLastNodeOf(word: word) { - return lastNode.isTerminating ? lastNode : nil + return lastNode.isTerminating ? lastNode : nil } return nil - } /// Deletes a word from the trie by starting with the last letter @@ -237,17 +235,17 @@ extension Trie { /// - prefix: the letters for word prefix /// - Returns: the words in the subtrie that start with prefix func findWordsWithPrefix(prefix: String) -> [String] { - var words = [String]() - let prefixLowerCased = prefix.lowercased() - if let lastNode = findLastNodeOf(word: prefixLowerCased) { - if lastNode.isTerminating { - words.append(prefixLowerCased) - } - for childNode in lastNode.children.values { - let childWords = wordsInSubtrie(rootNode: childNode, partialWord: prefixLowerCased) - words += childWords - } + var words = [String]() + let prefixLowerCased = prefix.lowercased() + if let lastNode = findLastNodeOf(word: prefixLowerCased) { + if lastNode.isTerminating { + words.append(prefixLowerCased) + } + for childNode in lastNode.children.values { + let childWords = wordsInSubtrie(rootNode: childNode, partialWord: prefixLowerCased) + words += childWords } - return words + } + return words } } diff --git a/Trie/Trie/Trie/ViewController.swift b/Trie/Trie/Trie/ViewController.swift index 928b01f4c..8ce34f6c7 100644 --- a/Trie/Trie/Trie/ViewController.swift +++ b/Trie/Trie/Trie/ViewController.swift @@ -10,16 +10,16 @@ import Cocoa class ViewController: NSViewController { - override func viewDidLoad() { - super.viewDidLoad() + override func viewDidLoad() { + super.viewDidLoad() - // Do any additional setup after loading the view. - } + // Do any additional setup after loading the view. + } - override var representedObject: Any? { - didSet { - // Update the view, if already loaded. - } + override var representedObject: Any? { + didSet { + // Update the view, if already loaded. } + } } diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index b69c5666e..0c5bc69c6 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -10,186 +10,184 @@ import XCTest @testable import Trie class TrieTests: XCTestCase { - var wordArray: [String]? - var trie = Trie() - - /// Makes sure that the wordArray and trie are initialized before each test. - override func setUp() { - super.setUp() - createWordArray() - insertWordsIntoTrie() + var wordArray: [String]? + var trie = Trie() + + /// Makes sure that the wordArray and trie are initialized before each test. + override func setUp() { + super.setUp() + createWordArray() + insertWordsIntoTrie() + } + + /// Don't need to do anything here because the wordArray and trie should + /// stay around. + override func tearDown() { + super.tearDown() + } + + /// Reads words from the dictionary file and inserts them into an array. If + /// the word array already has words, do nothing. This allows running all + /// tests without repeatedly filling the array with the same values. + func createWordArray() { + guard wordArray == nil else { + return } - - /// Don't need to do anything here because the wordArray and trie should - /// stay around. - override func tearDown() { - super.tearDown() - } - - /// Reads words from the dictionary file and inserts them into an array. If - /// the word array already has words, do nothing. This allows running all - /// tests without repeatedly filling the array with the same values. - func createWordArray() { - guard wordArray == nil else { - return - } - let resourcePath = Bundle.main.resourcePath! as NSString - let fileName = "dictionary.txt" - let filePath = resourcePath.appendingPathComponent(fileName) - - var data: String? - do { - data = try String(contentsOfFile: filePath, encoding: String.Encoding.utf8) - } catch let error as NSError { - XCTAssertNil(error) - } - XCTAssertNotNil(data) - let dictionarySize = 162825 - wordArray = data!.components(separatedBy: "\n") - XCTAssertEqual(wordArray!.count, dictionarySize) - } - - /// Inserts words into a trie. If the trie is non-empty, don't do anything. - func insertWordsIntoTrie() { - guard let wordArray = wordArray, trie.count == 0 else { return } - for word in wordArray { - trie.insert(word: word) - } - } - - /// Tests that a newly created trie has zero words. - func testCreate() { - let trie = Trie() - XCTAssertEqual(trie.count, 0) - } - - /// Tests the insert method - func testInsert() { - let trie = Trie() - trie.insert(word: "cute") - trie.insert(word: "cutie") - trie.insert(word: "fred") - XCTAssertTrue(trie.contains(word: "cute")) - XCTAssertFalse(trie.contains(word: "cut")) - trie.insert(word: "cut") - XCTAssertTrue(trie.contains(word: "cut")) - XCTAssertEqual(trie.count, 4) - } - - /// Tests the remove method - func testRemove() { - let trie = Trie() - trie.insert(word: "cute") - trie.insert(word: "cut") - XCTAssertEqual(trie.count, 2) - trie.remove(word: "cute") - XCTAssertTrue(trie.contains(word: "cut")) - XCTAssertFalse(trie.contains(word: "cute")) - XCTAssertEqual(trie.count, 1) + let resourcePath = Bundle.main.resourcePath! as NSString + let fileName = "dictionary.txt" + let filePath = resourcePath.appendingPathComponent(fileName) + + var data: String? + do { + data = try String(contentsOfFile: filePath, encoding: String.Encoding.utf8) + } catch let error as NSError { + XCTAssertNil(error) } - - /// Tests the words property - func testWords() { - let trie = Trie() - var words = trie.words - XCTAssertEqual(words.count, 0) - trie.insert(word: "foobar") - words = trie.words - XCTAssertEqual(words[0], "foobar") - XCTAssertEqual(words.count, 1) + XCTAssertNotNil(data) + let dictionarySize = 162825 + wordArray = data!.components(separatedBy: "\n") + XCTAssertEqual(wordArray!.count, dictionarySize) + } + + /// Inserts words into a trie. If the trie is non-empty, don't do anything. + func insertWordsIntoTrie() { + guard let wordArray = wordArray, trie.count == 0 else { return } + for word in wordArray { + trie.insert(word: word) } - - /// Tests the performance of the insert method. - func testInsertPerformance() { - self.measure { - let trie = Trie() - for word in self.wordArray! { - trie.insert(word: word) - } - } - XCTAssertGreaterThan(trie.count, 0) - XCTAssertEqual(trie.count, wordArray?.count) + } + + /// Tests that a newly created trie has zero words. + func testCreate() { + let trie = Trie() + XCTAssertEqual(trie.count, 0) + } + + /// Tests the insert method + func testInsert() { + let trie = Trie() + trie.insert(word: "cute") + trie.insert(word: "cutie") + trie.insert(word: "fred") + XCTAssertTrue(trie.contains(word: "cute")) + XCTAssertFalse(trie.contains(word: "cut")) + trie.insert(word: "cut") + XCTAssertTrue(trie.contains(word: "cut")) + XCTAssertEqual(trie.count, 4) + } + + /// Tests the remove method + func testRemove() { + let trie = Trie() + trie.insert(word: "cute") + trie.insert(word: "cut") + XCTAssertEqual(trie.count, 2) + trie.remove(word: "cute") + XCTAssertTrue(trie.contains(word: "cut")) + XCTAssertFalse(trie.contains(word: "cute")) + XCTAssertEqual(trie.count, 1) + } + + /// Tests the words property + func testWords() { + let trie = Trie() + var words = trie.words + XCTAssertEqual(words.count, 0) + trie.insert(word: "foobar") + words = trie.words + XCTAssertEqual(words[0], "foobar") + XCTAssertEqual(words.count, 1) + } + + /// Tests the performance of the insert method. + func testInsertPerformance() { + self.measure { + let trie = Trie() + for word in self.wordArray! { + trie.insert(word: word) + } } - - /// Tests the performance of the insert method when the words are already - /// present. - func testInsertAgainPerformance() { - self.measure { - for word in self.wordArray! { - self.trie.insert(word: word) - } - } + XCTAssertGreaterThan(trie.count, 0) + XCTAssertEqual(trie.count, wordArray?.count) + } + + /// Tests the performance of the insert method when the words are already + /// present. + func testInsertAgainPerformance() { + self.measure { + for word in self.wordArray! { + self.trie.insert(word: word) + } } - - /// Tests the performance of the contains method. - func testContainsPerformance() { - self.measure { - for word in self.wordArray! { - XCTAssertTrue(self.trie.contains(word: word)) - } - } + } + + /// Tests the performance of the contains method. + func testContainsPerformance() { + self.measure { + for word in self.wordArray! { + XCTAssertTrue(self.trie.contains(word: word)) + } } + } - /// Tests the performance of the remove method. Since setup has already put - /// words into the trie, remove them before measuring performance. - func testRemovePerformance() { - for word in self.wordArray! { - self.trie.remove(word: word) - } - self.measure { - self.insertWordsIntoTrie() - for word in self.wordArray! { - self.trie.remove(word: word) - } - } - XCTAssertEqual(trie.count, 0) + /// Tests the performance of the remove method. Since setup has already put + /// words into the trie, remove them before measuring performance. + func testRemovePerformance() { + for word in self.wordArray! { + self.trie.remove(word: word) } - - /// Tests the performance of the words computed property. Also tests to see - /// if it worked properly. - func testWordsPerformance() { - var words: [String]? - self.measure { - words = self.trie.words - } - XCTAssertEqual(words?.count, trie.count) - for word in words! { - XCTAssertTrue(self.trie.contains(word: word)) - } + self.measure { + self.insertWordsIntoTrie() + for word in self.wordArray! { + self.trie.remove(word: word) + } } - - /// Tests the archiving and unarchiving of the trie. - func testArchiveAndUnarchive() { - let resourcePath = Bundle.main.resourcePath! as NSString - let fileName = "dictionary-archive" - let filePath = resourcePath.appendingPathComponent(fileName) - NSKeyedArchiver.archiveRootObject(trie, toFile: filePath) - let trieCopy = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Trie - XCTAssertEqual(trieCopy?.count, trie.count) - + XCTAssertEqual(trie.count, 0) + } + + /// Tests the performance of the words computed property. Also tests to see + /// if it worked properly. + func testWordsPerformance() { + var words: [String]? + self.measure { + words = self.trie.words } - - func testFindWordsWithPrefix() { - let trie = Trie() - trie.insert(word: "test") - trie.insert(word: "another") - trie.insert(word: "exam") - let wordsAll = trie.findWordsWithPrefix(prefix: "") - XCTAssertEqual(wordsAll.sorted(), ["another", "exam", "test"]) - let words = trie.findWordsWithPrefix(prefix: "ex") - XCTAssertEqual(words, ["exam"]) - trie.insert(word: "examination") - let words2 = trie.findWordsWithPrefix(prefix: "exam") - XCTAssertEqual(words2, ["exam", "examination"]) - let noWords = trie.findWordsWithPrefix(prefix: "tee") - XCTAssertEqual(noWords, []) - let unicodeWord = "😬😎" - trie.insert(word: unicodeWord) - let wordsUnicode = trie.findWordsWithPrefix(prefix: "😬") - XCTAssertEqual(wordsUnicode, [unicodeWord]) - trie.insert(word: "Team") - let wordsUpperCase = trie.findWordsWithPrefix(prefix: "Te") - XCTAssertEqual(wordsUpperCase.sorted(), ["team", "test"]) - + XCTAssertEqual(words?.count, trie.count) + for word in words! { + XCTAssertTrue(self.trie.contains(word: word)) } + } + + /// Tests the archiving and unarchiving of the trie. + func testArchiveAndUnarchive() { + let resourcePath = Bundle.main.resourcePath! as NSString + let fileName = "dictionary-archive" + let filePath = resourcePath.appendingPathComponent(fileName) + NSKeyedArchiver.archiveRootObject(trie, toFile: filePath) + let trieCopy = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Trie + XCTAssertEqual(trieCopy?.count, trie.count) + } + + func testFindWordsWithPrefix() { + let trie = Trie() + trie.insert(word: "test") + trie.insert(word: "another") + trie.insert(word: "exam") + let wordsAll = trie.findWordsWithPrefix(prefix: "") + XCTAssertEqual(wordsAll.sorted(), ["another", "exam", "test"]) + let words = trie.findWordsWithPrefix(prefix: "ex") + XCTAssertEqual(words, ["exam"]) + trie.insert(word: "examination") + let words2 = trie.findWordsWithPrefix(prefix: "exam") + XCTAssertEqual(words2, ["exam", "examination"]) + let noWords = trie.findWordsWithPrefix(prefix: "tee") + XCTAssertEqual(noWords, []) + let unicodeWord = "😬😎" + trie.insert(word: unicodeWord) + let wordsUnicode = trie.findWordsWithPrefix(prefix: "😬") + XCTAssertEqual(wordsUnicode, [unicodeWord]) + trie.insert(word: "Team") + let wordsUpperCase = trie.findWordsWithPrefix(prefix: "Te") + XCTAssertEqual(wordsUpperCase.sorted(), ["team", "test"]) + } } diff --git a/Trie/Trie/TrieUITests/TrieUITests.swift b/Trie/Trie/TrieUITests/TrieUITests.swift index acb3b1756..380bf3092 100644 --- a/Trie/Trie/TrieUITests/TrieUITests.swift +++ b/Trie/Trie/TrieUITests/TrieUITests.swift @@ -10,27 +10,27 @@ import XCTest class TrieUITests: XCTestCase { - override func setUp() { - super.setUp() + override func setUp() { + super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. + // Put setup code here. This method is called before the invocation of each test method in the class. - // In UI tests it is usually best to stop immediately when a failure occurs. - continueAfterFailure = false - // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. - XCUIApplication().launch() + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. + XCUIApplication().launch() - // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. - } + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } - func testExample() { - // Use recording to get started writing UI tests. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } + func testExample() { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } } From 41eb9c1ee1591472c24b49108295261f698a3f1b Mon Sep 17 00:00:00 2001 From: Samwel Charles Date: Mon, 29 Oct 2018 00:22:43 +0300 Subject: [PATCH 221/327] update union-find to swift 4.2 --- Union-Find/UnionFind.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Union-Find/UnionFind.playground/Contents.swift b/Union-Find/UnionFind.playground/Contents.swift index 6ac3b4c4e..b1f7fb4e1 100644 --- a/Union-Find/UnionFind.playground/Contents.swift +++ b/Union-Find/UnionFind.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - var dsu = UnionFindQuickUnion() for i in 1...10 { diff --git a/Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From cb76b97e3f295d171267044ca599d27db113a7ee Mon Sep 17 00:00:00 2001 From: Samwel Charles Date: Mon, 29 Oct 2018 01:01:09 +0300 Subject: [PATCH 222/327] add link to merge sort algorithm in buble sort algorith README.md file --- Bubble Sort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index e55129d93..c4b2c37c8 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -117,7 +117,7 @@ There is no Fifth pass #### Conclusion -Even with the proposed optimizations, this is still a terribly inefficient sorting algorithm. A good alternative is [Merge Sort](), that not only is better performing, has a similar degree of dificulty to implement. +Even with the proposed optimizations, this is still a terribly inefficient sorting algorithm. A good alternative is [Merge Sort](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Merge%20Sort), that not only is better performing, has a similar degree of dificulty to implement. *Updated for the Swift Algorithm Club by Julio Brazil* From 299a67caeb984577561aaf1921271015558bfd6e Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 29 Oct 2018 11:45:21 -0300 Subject: [PATCH 223/327] addition of convenience method --- Bubble Sort/MyPlayground.playground/Contents.swift | 4 +++- .../MyPlayground.playground/Sources/BubbleSort.swift | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Bubble Sort/MyPlayground.playground/Contents.swift b/Bubble Sort/MyPlayground.playground/Contents.swift index 8d27d801e..6188a0763 100644 --- a/Bubble Sort/MyPlayground.playground/Contents.swift +++ b/Bubble Sort/MyPlayground.playground/Contents.swift @@ -3,4 +3,6 @@ import Foundation var array = [4,2,1,3] print("before:",array) -print("after:",BubbleSort(array)) +print("after:", bubbleSort(array)) +print("after:", bubbleSort(array, <)) +print("after:", bubbleSort(array, >)) diff --git a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift index 9c091b661..09e01542b 100644 --- a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift +++ b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift @@ -23,14 +23,18 @@ import Foundation /// Performs the bubble sort algorithm in the array /// -/// - Parameter elements: the array to be sorted +/// - Parameter elements: a array of elements that implement the Comparable protocol /// - Returns: an array with the same elements but in order -public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { +public func bubbleSort (_ elements: [T]) -> [T] where T: Comparable { + return bubbleSort(elements, <) +} + +public func bubbleSort (_ elements: [T], _ comparison: (T,T) -> Bool) -> [T] { var array = elements for i in 0.. Date: Tue, 30 Oct 2018 10:11:48 +0100 Subject: [PATCH 224/327] Removing unnecessary Error case for empty list * Was intended to be a second example, but is not yet implemented --- GCD/GCD.playground/Contents.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/GCD/GCD.playground/Contents.swift b/GCD/GCD.playground/Contents.swift index 9dfd7cca9..175d26639 100644 --- a/GCD/GCD.playground/Contents.swift +++ b/GCD/GCD.playground/Contents.swift @@ -106,7 +106,6 @@ func findEasySolution(_ m: Int, _ n: Int) -> Int? { enum LCMError: Error { case divisionByZero - case lcmEmptyList } /* From 34a6067355c2596754500ad309eb79bf540f135c Mon Sep 17 00:00:00 2001 From: cr0ss Date: Tue, 30 Oct 2018 10:12:34 +0100 Subject: [PATCH 225/327] Also removes the lcmEmptyList from the actual code file --- GCD/GCD.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/GCD/GCD.swift b/GCD/GCD.swift index 85b7681f0..f4b390e63 100644 --- a/GCD/GCD.swift +++ b/GCD/GCD.swift @@ -105,7 +105,6 @@ func findEasySolution(_ m: Int, _ n: Int) -> Int? { enum LCMError: Error { case divisionByZero - case lcmEmptyList } /* From 1e8e231d3cceb8d57a5bdf6838b4f8b544cdfe65 Mon Sep 17 00:00:00 2001 From: Randy the Dev <37282011+RandyTheDev@users.noreply.github.com> Date: Thu, 1 Nov 2018 06:55:11 +1100 Subject: [PATCH 226/327] Updated Run-Length Encoding to Swift 4.2 --- Run-Length Encoding/RLE.playground/Contents.swift | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Run-Length Encoding/RLE.playground/Contents.swift b/Run-Length Encoding/RLE.playground/Contents.swift index fc2d82505..8d6a0a403 100644 --- a/Run-Length Encoding/RLE.playground/Contents.swift +++ b/Run-Length Encoding/RLE.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation let originalString = "aaaaabbbcdeeeeeeef" @@ -64,7 +59,7 @@ func testBufferWithoutSpans() -> Bool { // data ends up being longer. var bytes: [UInt8] = [] for i in 0..<1024 { - bytes.append(UInt8(i%256)) + bytes.append(UInt8(i % 256)) } return encodeAndDecode(bytes) } From d454cf1e1b3a9b60bc005a8b3051be1d328d1932 Mon Sep 17 00:00:00 2001 From: Randy the Dev <37282011+RandyTheDev@users.noreply.github.com> Date: Thu, 1 Nov 2018 07:25:19 +1100 Subject: [PATCH 227/327] Confirmed Linear Regression to work with Swift 4.2 --- .../LinearRegression.playground/Contents.swift | 7 +------ Linear Regression/README.markdown | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index 3e4135794..a093ef566 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -2,11 +2,6 @@ import Foundation -// last checked with Xcode 4.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let carAge: [Double] = [10, 8, 3, 3, 2, 1] let carPrice: [Double] = [500, 400, 7000, 8500, 11000, 10500] var intercept = 0.0 @@ -22,7 +17,7 @@ let numberOfCarAdvertsWeSaw = carPrice.count let numberOfIterations = 100 let alpha = 0.0001 -for n in 1...numberOfIterations { +for _ in 1...numberOfIterations { for i in 0.. Date: Thu, 1 Nov 2018 07:35:17 +1100 Subject: [PATCH 228/327] Updated Minimum Edit Distance Playground for Swift 4.2 --- .../MinimumEditDistance.playground/Contents.swift | 12 ++++-------- Minimum Edit Distance/README.markdown | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift b/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift index 967e73182..5db0aeb0d 100644 --- a/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift +++ b/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift @@ -1,15 +1,11 @@ // Minimum Edit Distance -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif extension String { public func minimumEditDistance(other: String) -> Int { - let m = self.characters.count - let n = other.characters.count + let m = self.count + let n = other.count var matrix = [[Int]](repeating: [Int](repeating: 0, count: n + 1), count: m + 1) // initialize matrix @@ -24,8 +20,8 @@ extension String { } // compute Levenshtein distance - for (i, selfChar) in self.characters.enumerated() { - for (j, otherChar) in other.characters.enumerated() { + for (i, selfChar) in self.enumerated() { + for (j, otherChar) in other.enumerated() { if otherChar == selfChar { // substitution of equal symbols with cost 0 matrix[i + 1][j + 1] = matrix[i][j] diff --git a/Minimum Edit Distance/README.markdown b/Minimum Edit Distance/README.markdown index b8880b2d4..c8e5e2f6d 100755 --- a/Minimum Edit Distance/README.markdown +++ b/Minimum Edit Distance/README.markdown @@ -37,8 +37,8 @@ Then in each cell the minimum of the cost of insertion, deletion, or substitutio ```swift // compute Levenshtein distance -for (i, selfChar) in self.characters.enumerated() { - for (j, otherChar) in other.characters.enumerated() { +for (i, selfChar) in self.enumerated() { + for (j, otherChar) in other.enumerated() { if otherChar == selfChar { // substitution of equal symbols with cost 0 matrix[i + 1][j + 1] = matrix[i][j] From eea4cfc6eaba53d86c3a383b1dce9c3c374b3ebd Mon Sep 17 00:00:00 2001 From: iillx Date: Wed, 31 Oct 2018 22:56:29 -0300 Subject: [PATCH 229/327] Counting Sort working with Swift 4.2 --- Counting Sort/CountingSort.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Counting Sort/CountingSort.playground/Contents.swift b/Counting Sort/CountingSort.playground/Contents.swift index 4d918e384..dc375512a 100644 --- a/Counting Sort/CountingSort.playground/Contents.swift +++ b/Counting Sort/CountingSort.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - enum CountingSortError: Error { case arrayEmpty } From 43e76adfc53c5cadde2511e9fc80fa3c59114be9 Mon Sep 17 00:00:00 2001 From: iillx Date: Wed, 31 Oct 2018 23:10:55 -0300 Subject: [PATCH 230/327] Union Find working with Swift 4.2 and Xcode 10 --- Union-Find/UnionFind.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Union-Find/UnionFind.playground/Contents.swift b/Union-Find/UnionFind.playground/Contents.swift index 6ac3b4c4e..b1f7fb4e1 100644 --- a/Union-Find/UnionFind.playground/Contents.swift +++ b/Union-Find/UnionFind.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - var dsu = UnionFindQuickUnion() for i in 1...10 { From 6707ce26934addaceff3d54ee417632e210443df Mon Sep 17 00:00:00 2001 From: iillx Date: Wed, 31 Oct 2018 23:16:04 -0300 Subject: [PATCH 231/327] Shunting Yard working fine with Swift 4.2 and Xcode 10 --- Shunting Yard/ShuntingYard.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Shunting Yard/ShuntingYard.playground/Contents.swift b/Shunting Yard/ShuntingYard.playground/Contents.swift index ddd73de59..38431f5e2 100644 --- a/Shunting Yard/ShuntingYard.playground/Contents.swift +++ b/Shunting Yard/ShuntingYard.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - internal enum OperatorAssociativity { case leftAssociative case rightAssociative diff --git a/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From a1d65fcba404f8a59897c46480e54cadbe491b63 Mon Sep 17 00:00:00 2001 From: iillx Date: Wed, 31 Oct 2018 23:25:54 -0300 Subject: [PATCH 232/327] Updated random number generation to Swift 4.2 --- Set Cover (Unweighted)/SetCover.playground/Contents.swift | 7 ++----- .../SetCover.playground/Sources/RandomArrayOfSets.swift | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Set Cover (Unweighted)/SetCover.playground/Contents.swift b/Set Cover (Unweighted)/SetCover.playground/Contents.swift index d61b9c84a..065f5fd4d 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Contents.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Contents.swift @@ -1,10 +1,5 @@ // SetCover -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let universe1 = Set(1...7) let array1 = randomArrayOfSets(covering: universe1) let cover1 = universe1.cover(within: array1) @@ -36,3 +31,5 @@ let emptySet = Set() let coverTest1 = emptySet.cover(within: array1) let coverTest2 = universe1.cover(within: Array>()) let coverTest3 = emptySet.cover(within: Array>()) + + diff --git a/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift index 9454c6383..ac4ff063e 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift @@ -14,10 +14,10 @@ public func randomArrayOfSets(covering universe: Set, while true { var generatedSet = Set() - let targetSetSize = Int(arc4random_uniform(UInt32(maxSetSize)) + 1) + let targetSetSize = Int.random(in: 0...maxSetSize) + 1 while true { - let randomUniverseIndex = Int(arc4random_uniform(UInt32(universe.count))) + let randomUniverseIndex = Int.random(in: 0...universe.count) for (setIndex, value) in universe.enumerated() { if setIndex == randomUniverseIndex { generatedSet.insert(value) From f37fb19f054c95b654e07186d5f6fc5cf56bb12d Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 1 Nov 2018 20:55:17 +0100 Subject: [PATCH 233/327] Update README according to comments. --- Bloom Filter/README.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Bloom Filter/README.markdown b/Bloom Filter/README.markdown index 4364db857..5f2ede069 100644 --- a/Bloom Filter/README.markdown +++ b/Bloom Filter/README.markdown @@ -102,7 +102,9 @@ If you're coming from another imperative language, you might notice the unusual ## Another approach -Another approach to create different hashes of an element for use in the Bloom filter, is to use the same hash function for every iteration, but combine it with different random numbers. This can help, because finding good hashing functions is hard, but combining them is equally non-trivial. +In the previous section, you learnt about how using multiple different hash functions can help reduce the chance of collisions in the bloom filter. However, good hash functions are difficult to design. A simple alternative to multiple hash functions is to use a set of random numbers. + +As an example, let's say a bloom filter wants to hash each element 15 times during insertion. Instead of using 15 different hash functions, you can rely on just one hash function. The hash value can then be combined with 15 different values to form the indices for flipping. This bloom filter would initialize a set of 15 random numbers ahead of time and use these values during each insertion. ``` hash("Hello world!") >> hash(987654321) // would flip bit 8 From f9133844436bd6336595e0f6b66038f676dd3b3a Mon Sep 17 00:00:00 2001 From: gmotzespina Date: Mon, 5 Nov 2018 19:00:34 -0600 Subject: [PATCH 234/327] Swift 4.2 Migration #748 - Depth First Search migrated to Swift 4.2 --- .../APSP/APSP.xcodeproj/project.pbxproj | 8 +++++--- .../Pages/Simple Example.xcplaygroundpage/Contents.swift | 5 +---- Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj index 78df3fb76..908d32785 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj @@ -196,7 +196,7 @@ }; 493D8DF01CDD5B960089795A = { CreatedOnToolsVersion = 7.3; - LastSwiftMigration = 0820; + LastSwiftMigration = 1010; }; }; }; @@ -420,7 +420,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -442,7 +443,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; diff --git a/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/Contents.swift b/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/Contents.swift index 99f20a729..c83f52af8 100644 --- a/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/Contents.swift +++ b/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/Contents.swift @@ -1,7 +1,4 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +// last checked with Xcode 10.1 func depthFirstSearch(_ graph: Graph, source: Node) -> [String] { var nodesExplored = [source.label] diff --git a/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj index 8f6058600..2b433bd96 100644 --- a/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj +++ b/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -234,7 +234,7 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -247,7 +247,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; From 0f739b5230f7fe0df655fac82941e9111d346b90 Mon Sep 17 00:00:00 2001 From: gmotzespina Date: Mon, 5 Nov 2018 19:08:43 -0600 Subject: [PATCH 235/327] Swift 4.2 support Depth-First Search --- .../DepthFirstSearch.playground/Edge.o | Bin 0 -> 7016 bytes .../DepthFirstSearch.playground/Graph.o | Bin 0 -> 21488 bytes .../DepthFirstSearch.playground/Node.o | Bin 0 -> 19288 bytes .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/WorkspaceSettings.xcsettings | 8 ++++++++ 5 files changed, 16 insertions(+) create mode 100644 Depth-First Search/DepthFirstSearch.playground/Edge.o create mode 100644 Depth-First Search/DepthFirstSearch.playground/Graph.o create mode 100644 Depth-First Search/DepthFirstSearch.playground/Node.o create mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/Depth-First Search/DepthFirstSearch.playground/Edge.o b/Depth-First Search/DepthFirstSearch.playground/Edge.o new file mode 100644 index 0000000000000000000000000000000000000000..ab1e89b3aa83ed547413ba061a5edfd5dc918137 GIT binary patch literal 7016 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 literal 0 HcmV?d00001 diff --git a/Depth-First Search/DepthFirstSearch.playground/Graph.o b/Depth-First Search/DepthFirstSearch.playground/Graph.o new file mode 100644 index 0000000000000000000000000000000000000000..dde35fb0f1a416f1a99b083ab8937861bd8038af GIT binary patch literal 21488 zcmdUX4|H5db@#KeV+G5y2oOxbWFe+8A+{yQ{}Pg-wY>IIBE_;-vR&eIwU$=WCac{= zyK74ZwQIx{J-=)#dQj_A(pLRL>$aGxr*)4K&_OY7EK*2R4kT{-rHJp)Rw1TUIR#8g zP=CLf`*zYYbz>8w~t|5AKcW8}N@0 zA6#$8XMVN1E&I=g&ANDwGPtU4*GN75+@wh(6iP=1(n0`2p|-%Wwj%A^J`>IV&)?=R(&M7X$4=qO`V518JhsCy-ogUU6$*8x(*4nR zkCc1uo4!R?tP_3X@7DG?YF0Wo1^LveXm@%?C_R{r^hdhA`o8)O&G?A$UwDtcxeoh8 zSFKbj2!%vnXE>S8^hdn<_PkSb*NM=E+q9mlorWQy@#yPJ#8c@)6JG!IioUDDVL~7M zw+H%s1*zf<{O8eE8sCPEn)i~3_%?~YU6u5mNTrJEm&CVL##xobgRC4c&gCjrMWImQ z#3P+WBfb5tdY6`*6b18+eY*?(b5x5yi3egE!^rW*V_Niy?~U>ImWY$^#6$FTM3sXP=&KU5E{nc%&?kN@uaDyyf$`dRP4qc2 z_=@P8guZ3QbEq%T)f-OrLSJ+9krpuqups&zBW9QSugHu$C%&<8Diw>S(%$$Qw`z8$ zzjM&X@jL_jWUM$%DMry3?F;urqVev8S6`J!-~3YhJo-8leaUcVI+Tf@ipCM&=6%{C z{co-4%hD)Z3u50a?30*_8+Cms6zL6h_lNr;4qZCmM&F~$2P7cL_v!xXQo~q_q2t^W zx8t(`AJxc;Y8I)BG|MOU7{+73q#wByNgeV=D?YrC8q^0Y#zXkj2=rSA2& zew-pozrP(V>@lsOt58)C1Lu|6C*BPnw%45RLqq>URbZMfsW7gHG*` zm^FNPkN@F^zqI~Vj2P7)>xYUJW{i^dx3@M8{}t6#O{(@THCz9RRu;6v{99=#I=2AZ ztEj2Fd+QSWH`GsCSCqgL^sn{o6I{OOiJ=8LisDu~e0E7OHCcb9wGUt3pp7f~1Kxl! zt5vJR*A4Xfdgc~0e;+4=7NX;Iy)|?ls;}37*?I=n)zUUzCH6sI2dsMvaY3&Tjut0g zL-53k!cT|FBT48?hu1Z?8SIEbL|{DtBoF-Q3EP74dW+ae8Co!2hPJ%rx`HX;IjKr z7&xb!VXxtNJ21)N>$VkLzXIL~XdG>}UIN>Q(@AL|&&WLuo)I*X)s=be_S|&(rk4#< zC@VLxxVZT8%9jtDwz@?)o-^%sSlbTQ=8~ut@yt~-KQ!BH2cUDR7v;^gBF8(^8tYI6 zmoPY>h*FEQFn!cKbD8eoIFb2Sr(9#}kvaT|fl+oHjltfQ`HVTa2yPjT@HlD^TbPrtOF5yq;0+O+RMkIq4^$@&H?z+GT;@lZ#getI7UXkMA5qGDQk z`d)XNtw(9>A%wL?Ixp7B{TE?f&DG4P1+^D)68!6P=Q@SXZEf(ci zjnVR(*vsgZ?wKdlfU%y3rv^}o1qqptH~CmWPABXME(6HbPA0#olvy{J){!dMNk?Jm znD*gb4xg{VTSx%yt7^0fbLOoYsz5RLCv{esvxVZ4)PzMiN$y)PD16O~}BL((40yZyM z=3v_i_A&O*x`eUD$Tr)bDFmb0`j$ETBcs{+OsnF_nSk}VPs6tmCxNk{#d8gyWXKHZ zYXc22|8Ri!RhTa;1v7=4`oFa7&}fEjD9w2tkl&289Jl@>D;j9q`V#E9HN zfwsqla~?&eHH+Yr8EY~VrvEq-yk0*gF8Mh}cKuqlzbv<(yA2|GyQrpL`+|7ylId*h z+SSHRHg$#dw$-%PnAW|UASE4Iwdv

    oMAESZ;sNUa~*XDf_D99<-W46eQ|}%>q)l zXS0BkN}C1b_!)S42F7!*@7|BTmi@0)FZ-Wb)3ZPR@ARiSpKPGx?FM9qSGmaVG3{Su zc0z7iSbPD=WdU~>R?aRchuLdAJ*f^T zJnN{~^MKSK=do5;(qw09o9y-tus{Z9;q9?eF-G>#gto$+)1T3c z*t1|hZ(7e|!v|;|Z$@@6o+U29_Y*43+e1(}0N>Etqu`XYgH{PPELQE%5RhX7)VLN2 zEJM%&=^r9V4KP7k?!D^Jw6>4CcK68uIr>;3jp_vkD+@YwQR%RC%C(+qwj)|Y)9{ZC zsAz@I`rLc<5<&t=R~7}cpbyKVcx7nbxxtvrlLJEluFEy3TeTAt4vt8@GqZAas`fex zXe5kc0k$uWGA9A!td0c^>NYEZybqvuP`p9$2EfZbFB|;N%&&gvja*s3Wm+q)_&IK| z74>i6%@sfMFUhKYV*bAGkTt*Vj{r~d`HJ=YlXnCB*6fqyw8q{7)%)x`L0PqaEmje> z$7Bxolq7TQp?sCY%ngJ{dB(rW51VyZs=b0dLo zs{6BnZ(=-e<{WnBAJ>Z}d#D!YT|Hk)CoBwcrcvR*UsxZQADx-2^n3Cz>-F=NW(%pr z$v@0J|JTH{Y_=lvBY}Tr`pMjM7B{fF$@&URRL@YDh>B?j{c|20*i2P{>4p((pd;8E zYj*v7rPTZi`DV_s8fsoU-_)A_MfqR+apu}2vj^5>oOE=It^{TMYw|80PNH2kt@N2och{b(1-Elgh3fvLZMZY@PSU~Y z*|gWINtCNX4Gv5=?oWeZhU3e$mbj>pV4SR}&u@7o|2!W(O!DIh1b3lYY1tzk)`KzGs7_NE_mTRH zXJ2H2D^ZR+Y9>)Gp+1KeCJHUEReOpwEIqG)ZsDB{^>~5R#?eXl@Epoi4|xN*Q2=_l zRxb;rknPzw(|(iEqKOb*v!FAo^*KXMOnJydP(NfxyW@fYTVy5ws)_1zQC9TWKQiOPT1RnYxVJkb@o$7lE=T|JQ$ZXPaaa$9>U z(x2Ma)0aq}j--;&czD~sNb1paBDqa{iMAyi>q+!S)4hFLI%Am=s7$7Nx9pGhr_#P) zB;4QGtBX{LF4&rkg$H~36Pb9|wqPRD-x*15JJ26a_HI=gOPV*@EE6&Iht_gV$r%>=3H$K#}edoF&^3MA~ zY_AHREIzbPJxv8V*XwOh4}3?OZC9)I={v^ryu2qt-;(QBI&c2^g~?Ao_W6IUf5%(b zZhxsLX&4>O%P1&3sw>=GQ6(L^+;|lD24lsN`dO*3(YU03PU`t=ww%0AB+Lr+(^CJt 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 literal 0 HcmV?d00001 diff --git a/Depth-First Search/DepthFirstSearch.playground/Node.o b/Depth-First Search/DepthFirstSearch.playground/Node.o new file mode 100644 index 0000000000000000000000000000000000000000..1090b3a9cbf150965dc206734fec12c24cda0982 GIT binary patch literal 19288 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 WO2$%2gh>zf&_PY60#Acy_5T4cZe^PQ literal 0 HcmV?d00001 diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + From 07732e85027602ed909f9afbd9ebb2869ba18632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Salda=C3=B1a?= Date: Mon, 5 Nov 2018 19:18:53 -0600 Subject: [PATCH 236/327] fix deprecated methods and return type --- .../BoyerMooreHorspool.playground/Contents.swift | 10 +++++----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../BoyerMooreHorspool.playground/timeline.xctimeline | 6 +++--- Boyer-Moore-Horspool/BoyerMooreHorspool.swift | 10 +++++----- 4 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift index e88a1b93d..c51070caf 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -13,16 +13,16 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { + func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Int? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= self.count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } @@ -57,7 +57,7 @@ extension String { if c == lastChar { // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k } + if let k = backwards() { return k.encodedOffset } if !usingHorspoolImprovement { // If no match, we can only safely skip one character ahead. diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline index 89bc76f90..431d4a349 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift index af8aea9d9..92d2ee4c1 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift @@ -6,16 +6,16 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { + func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Int? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= self.count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } @@ -50,7 +50,7 @@ extension String { if c == lastChar { // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k } + if let k = backwards() { return k.encodedOffset } if !usingHorspoolImprovement { // If no match, we can only safely skip one character ahead. From 17990d8b52ae03bae0570f5e97e18d5f75485136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Salda=C3=B1a?= Date: Mon, 5 Nov 2018 19:37:55 -0600 Subject: [PATCH 237/327] change return type --- .../BoyerMooreHorspool.playground/Contents.swift | 4 ++-- .../BoyerMooreHorspool.playground/timeline.xctimeline | 6 +++--- Boyer-Moore-Horspool/BoyerMooreHorspool.swift | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift index c51070caf..eba2a5806 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -13,7 +13,7 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Int? { + func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. let patternLength = pattern.count @@ -57,7 +57,7 @@ extension String { if c == lastChar { // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k.encodedOffset } + if let k = backwards() { return k } if !usingHorspoolImprovement { // If no match, we can only safely skip one character ahead. diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline index 431d4a349..5eb7f2337 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift index 92d2ee4c1..1dd37873a 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift @@ -6,7 +6,7 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Int? { + func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. let patternLength = pattern.count @@ -50,7 +50,7 @@ extension String { if c == lastChar { // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k.encodedOffset } + if let k = backwards() { return k } if !usingHorspoolImprovement { // If no match, we can only safely skip one character ahead. From a7047d8bbb8cbdc023c8979dcfa22d15ba6ed21f Mon Sep 17 00:00:00 2001 From: Morgan Davison Date: Tue, 6 Nov 2018 20:09:29 -0500 Subject: [PATCH 238/327] Compile for Swift 4.2 --- B-Tree/BTree.playground/Contents.swift | 5 +--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++++ B-Tree/Tests/Tests.xcodeproj/project.pbxproj | 24 +++++++++++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 5 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/B-Tree/BTree.playground/Contents.swift b/B-Tree/BTree.playground/Contents.swift index a0643586f..f6325513a 100644 --- a/B-Tree/BTree.playground/Contents.swift +++ b/B-Tree/BTree.playground/Contents.swift @@ -2,10 +2,7 @@ import Foundation -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +// last checked with Xcode 10.0 let bTree = BTree(order: 1)! diff --git a/B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/B-Tree/Tests/Tests.xcodeproj/project.pbxproj b/B-Tree/Tests/Tests.xcodeproj/project.pbxproj index 3e12b9ac3..66eb85190 100644 --- a/B-Tree/Tests/Tests.xcodeproj/project.pbxproj +++ b/B-Tree/Tests/Tests.xcodeproj/project.pbxproj @@ -85,12 +85,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Viktor Szilárd Simkó"; TargetAttributes = { C66702771D0EEE25008CD769 = { CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 0800; + LastSwiftMigration = 1000; }; }; }; @@ -144,14 +144,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -192,14 +200,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -234,7 +250,7 @@ PRODUCT_BUNDLE_IDENTIFIER = viktorsimko.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -247,7 +263,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = viktorsimko.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 9d6c542ae..d1555acfb 100644 --- a/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Wed, 7 Nov 2018 22:38:11 -0800 Subject: [PATCH 239/327] Added Markdown Documentation to Stack playground This might be overkill for such a small file, but I wish I started using Swift Markdown early in my iOS career. Option click is too convenient to ignore! --- Stack/Stack.playground/Contents.swift | 28 +++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index 1eb705f20..13774d7d1 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -1,4 +1,4 @@ -/* +/** Stack A stack is like an array but with limited functionality. You can only push @@ -9,27 +9,51 @@ last is the first one to come off with the next pop. Push and pop are O(1) operations. + + ## Usage + ``` + var myStack = Stack(array: []) + myStack.push(10) + myStack.push(3) + myStack.push(57) + myStack.pop() // 57 + myStack.pop() // 3 + ``` */ - public struct Stack { + + /// Datastructure consisting of a generic item. fileprivate var array = [T]() + /// The number of items in the stack. public var count: Int { return array.count } + /// Verifies if the stack is empty. public var isEmpty: Bool { return array.isEmpty } + /** + Pushes an item to the top of the stack. + + - Parameter element: The item being pushed. + */ public mutating func push(_ element: T) { array.append(element) } + /** + Removes and returns the item at the top of the sack. + + - Returns: The item at the top of the stack. + */ public mutating func pop() -> T? { return array.popLast() } + /// Returns the item at the top of the stack. public var top: T? { return array.last } From eb228cc1d18d860ad825c7d79063524121555bce Mon Sep 17 00:00:00 2001 From: Kelvin Reid Date: Sun, 11 Nov 2018 21:24:07 -0500 Subject: [PATCH 240/327] [Swift 4.2] Updated Hash Set --- Hash Set/HashSet.playground/Contents.swift | 4 ---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Hash Set/HashSet.playground/Contents.swift b/Hash Set/HashSet.playground/Contents.swift index 5edb76bb4..551c6dc86 100644 --- a/Hash Set/HashSet.playground/Contents.swift +++ b/Hash Set/HashSet.playground/Contents.swift @@ -1,8 +1,4 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif var set = HashSet() diff --git a/Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 67ecddaafb2e7637da0b24787ece79cadd82603c Mon Sep 17 00:00:00 2001 From: Kelvin Reid Date: Sun, 11 Nov 2018 21:37:44 -0500 Subject: [PATCH 241/327] [Swift 4.2] Updated Hash Table --- Hash Table/HashTable.playground/Contents.swift | 3 --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Hash Table/HashTable.playground/Contents.swift b/Hash Table/HashTable.playground/Contents.swift index 273113440..121fb6032 100644 --- a/Hash Table/HashTable.playground/Contents.swift +++ b/Hash Table/HashTable.playground/Contents.swift @@ -1,8 +1,5 @@ //: Playground - noun: a place where people can play -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif // Playing with hash values "firstName".hashValue diff --git a/Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 70d26fccdea4e655986b0fe36cec2d2dae2ab8e8 Mon Sep 17 00:00:00 2001 From: Kelvin Reid Date: Sun, 11 Nov 2018 21:44:55 -0500 Subject: [PATCH 242/327] [Swift 4.2] Updated Heap Sort --- Heap Sort/Tests/HeapSortTests.swift | 6 ---- .../Tests/Tests.xcodeproj/project.pbxproj | 31 +++++++++++++------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../xcshareddata/xcschemes/Tests.xcscheme | 4 +-- 4 files changed, 31 insertions(+), 18 deletions(-) create mode 100644 Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Heap Sort/Tests/HeapSortTests.swift b/Heap Sort/Tests/HeapSortTests.swift index b36f605e3..dae1f8a68 100644 --- a/Heap Sort/Tests/HeapSortTests.swift +++ b/Heap Sort/Tests/HeapSortTests.swift @@ -1,12 +1,6 @@ import XCTest class HeapSortTests: XCTestCase { - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } func testSort() { var h1 = Heap(array: [5, 13, 2, 25, 7, 17, 20, 8, 4], sort: >) diff --git a/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj b/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj index ff1f4937f..62e6d4e3f 100644 --- a/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ @@ -86,17 +86,17 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0820; + LastSwiftMigration = 1010; }; }; }; buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 10.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -149,12 +149,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -201,12 +203,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -230,7 +234,8 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; @@ -239,10 +244,14 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -251,10 +260,14 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 538a6f4fa..1608804f9 100644 --- a/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Sun, 11 Nov 2018 21:49:37 -0500 Subject: [PATCH 243/327] [Swift 4.2] Updated Heap --- Heap/Tests/HeapTests.swift | 7 ----- Heap/Tests/Tests.xcodeproj/project.pbxproj | 31 +++++++++++++------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../xcshareddata/xcschemes/Tests.xcscheme | 4 +-- 4 files changed, 31 insertions(+), 19 deletions(-) create mode 100644 Heap/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Heap/Tests/HeapTests.swift b/Heap/Tests/HeapTests.swift index 1ed15c726..ecf143778 100755 --- a/Heap/Tests/HeapTests.swift +++ b/Heap/Tests/HeapTests.swift @@ -7,13 +7,6 @@ import XCTest class HeapTests: XCTestCase { - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } - fileprivate func verifyMaxHeap(_ h: Heap) -> Bool { for i in 0.. + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 77d01bebc..1608804f9 100755 --- a/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Sun, 11 Nov 2018 23:00:22 -0500 Subject: [PATCH 244/327] Update Contents.swift --- HaversineDistance/HaversineDistance.playground/Contents.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/HaversineDistance/HaversineDistance.playground/Contents.swift b/HaversineDistance/HaversineDistance.playground/Contents.swift index 7aa686645..3d8d60f54 100644 --- a/HaversineDistance/HaversineDistance.playground/Contents.swift +++ b/HaversineDistance/HaversineDistance.playground/Contents.swift @@ -1,8 +1,4 @@ import UIKit -// last checked with Xcode 9.04 -#if swift(>=4) -print("Hello, Swift 4!") -#endif func haversineDinstance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double { From ef4e890fd9f5b0ddf15cfa289fc2993ee46a9e04 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 11 Nov 2018 23:01:46 -0500 Subject: [PATCH 245/327] Updates Contents.swift --- .../BoyerMooreHorspool.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift index 5817cc41f..1666549c1 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - /* Boyer-Moore string search From 9ba8b54dc580cc6cb3803a1a2cd2a9efcd5bf6ab Mon Sep 17 00:00:00 2001 From: gmotzespina Date: Mon, 12 Nov 2018 19:53:38 -0600 Subject: [PATCH 246/327] Bubble Sort Readme Code Issue #838 solved --- Bubble Sort/README.markdown | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index e55129d93..648b9f324 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -57,9 +57,9 @@ This is the same for the forth and fifth passes. ```swift for i in 0.. Date: Tue, 27 Nov 2018 14:22:02 -0600 Subject: [PATCH 247/327] Removing version check --- Tree/Tree.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Tree/Tree.playground/Contents.swift b/Tree/Tree.playground/Contents.swift index 06f992fa8..1fad157a0 100644 --- a/Tree/Tree.playground/Contents.swift +++ b/Tree/Tree.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.2) -print("Hello, Swift 4.2!") -#endif - let tree = TreeNode(value: "beverages") let hotNode = TreeNode(value: "hot") From f1363dd983ccacf1e48d9d393022f3ce68ba3c39 Mon Sep 17 00:00:00 2001 From: Francesco Scalise Date: Tue, 4 Dec 2018 19:31:26 +0100 Subject: [PATCH 248/327] [Swift 4.2] Count occurences --- Count Occurrences/CountOccurrences.playground/Contents.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Count Occurrences/CountOccurrences.playground/Contents.swift b/Count Occurrences/CountOccurrences.playground/Contents.swift index 6138b74ac..a34e3485f 100644 --- a/Count Occurrences/CountOccurrences.playground/Contents.swift +++ b/Count Occurrences/CountOccurrences.playground/Contents.swift @@ -1,7 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { func leftBoundary() -> Int { From a2953343f16129995f90cfc6cf49236b3bcb9ae5 Mon Sep 17 00:00:00 2001 From: Morgan Kan Date: Sun, 16 Dec 2018 21:46:06 +0000 Subject: [PATCH 249/327] Implement bit shift operations in BitSet --- Bit Set/BitSet.playground/Contents.swift | 20 ++++++++ .../BitSet.playground/Sources/BitSet.swift | 46 +++++++++++++++++- Bit Set/BitSet.swift | 47 ++++++++++++++++++- 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index d11b36e8c..2c5edcd84 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -89,3 +89,23 @@ z.all1() // false //var bigBits = BitSet(size: 10000) //print(bigBits) + +var smallBitSet = BitSet(size: 16) +smallBitSet[5] = true +smallBitSet[10] = true +print( smallBitSet >> 3 ) +print( smallBitSet << 6 ) // one bit shifts off the end + +var bigBitSet = BitSet( size: 120 ) +bigBitSet[1] = true +bigBitSet[3] = true +bigBitSet[7] = true +bigBitSet[32] = true +bigBitSet[55] = true +bigBitSet[64] = true +bigBitSet[80] = true +print( bigBitSet ) +print( bigBitSet << 32 ) +print( bigBitSet << 64 ) +print( bigBitSet >> 32 ) +print( bigBitSet >> 64 ) diff --git a/Bit Set/BitSet.playground/Sources/BitSet.swift b/Bit Set/BitSet.playground/Sources/BitSet.swift index 59306f5a5..85f5da505 100644 --- a/Bit Set/BitSet.playground/Sources/BitSet.swift +++ b/Bit Set/BitSet.playground/Sources/BitSet.swift @@ -9,7 +9,7 @@ public struct BitSet { We store the bits in a list of unsigned 64-bit integers. The first entry, `words[0]`, is the least significant word. */ - private let N = 64 + fileprivate let N = 64 public typealias Word = UInt64 fileprivate(set) public var words: [Word] @@ -221,6 +221,50 @@ prefix public func ~ (rhs: BitSet) -> BitSet { return out } +// MARK: - Bit shift operations + +/* + Note: For bitshift operations, the assumption is that any bits that are + shifted off the end of the end of the declared size are not still set. + In other words, we are maintaining the original number of bits. + */ + +public func << (lhs: BitSet, numBitsLeft: Int) -> BitSet { + var out = lhs + let offset = numBitsLeft / lhs.N + let shift = numBitsLeft % lhs.N + for i in 0..= 0 ) { + out.words[i] = lhs.words[i - offset] << shift + } + if( i - offset - 1 >= 0 ) { + out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} + +public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { + var out = lhs + let offset = numBitsRight / lhs.N + let shift = numBitsRight % lhs.N + for i in 0..> shift + } + if( i + offset + 1 < lhs.words.count ) { + out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} + // MARK: - Debugging extension UInt64 { diff --git a/Bit Set/BitSet.swift b/Bit Set/BitSet.swift index cfe8517b5..83829c6c5 100644 --- a/Bit Set/BitSet.swift +++ b/Bit Set/BitSet.swift @@ -9,7 +9,7 @@ public struct BitSet { We store the bits in a list of unsigned 64-bit integers. The first entry, `words[0]`, is the least significant word. */ - private let N = 64 + fileprivate let N = 64 public typealias Word = UInt64 fileprivate(set) public var words: [Word] @@ -221,6 +221,51 @@ prefix public func ~ (rhs: BitSet) -> BitSet { return out } +// MARK: - Bit shift operations + +/* + Note: For bitshift operations, the assumption is that any bits that are + shifted off the end of the end of the declared size are not still set. + In other words, we are maintaining the original number of bits. + */ + +public func << (lhs: BitSet, numBitsLeft: Int) -> BitSet { + var out = lhs + let offset = numBitsLeft / lhs.N + let shift = numBitsLeft % lhs.N + for i in 0..= 0 ) { + out.words[i] = lhs.words[i - offset] << shift + } + if( i - offset - 1 >= 0 ) { + out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} + +public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { + var out = lhs + let offset = numBitsRight / lhs.N + let shift = numBitsRight % lhs.N + for i in 0..> shift + } + if( i + offset + 1 < lhs.words.count ) { + out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} + + // MARK: - Debugging extension UInt64 { From dd182db605004ecdea85cf9b95de13b4006d52e3 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 20 Dec 2018 19:36:18 -0500 Subject: [PATCH 250/327] Fixes a typo --- A-Star/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/A-Star/README.md b/A-Star/README.md index f362bb61e..b373d25fc 100644 --- a/A-Star/README.md +++ b/A-Star/README.md @@ -16,7 +16,7 @@ On the first step we expand the root node on the left (blue). We set the cost `g ![Step 1](Images/step1.png) -We put the first not in the closed list (light blue) so that we don't try expanding it again if there were to be loops in the graph. Next we take the node on the open list with the smallest value of `g + h` where `g` is the current cost (0) plus the edge cost (1). Since all nodes in the open list have the same value we choose the top one. +We put the first node in the closed list (light blue) so that we don't try expanding it again if there were to be loops in the graph. Next we take the node on the open list with the smallest value of `g + h` where `g` is the current cost (0) plus the edge cost (1). Since all nodes in the open list have the same value we choose the top one. ![Step 2](Images/step2.png) From 1f15eda576530fdf76bb8245eecb99a5b4233a48 Mon Sep 17 00:00:00 2001 From: Andrzej Michnia Date: Sun, 16 Dec 2018 22:44:30 +0100 Subject: [PATCH 251/327] Fixed error in description --- Comb Sort/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Comb Sort/README.markdown b/Comb Sort/README.markdown index d30d429b3..20c939307 100644 --- a/Comb Sort/README.markdown +++ b/Comb Sort/README.markdown @@ -64,8 +64,8 @@ This will sort the values of the array into ascending order -- increasing in val ## Performance Comb Sort was created to improve upon the worst case time complexity of Bubble Sort. With Comb -Sort, the worst case scenario for performance is exponential -- O(n^2). At best though, Comb Sort -performs at O(n logn) time complexity. This creates a drastic improvement over Bubble Sort's performance. +Sort, the worst case scenario for performance is polynomial -- O(n^2). At best though, Comb Sort +performs at O(n logn) time complexity -- loglinear. This creates a drastic improvement over Bubble Sort's performance. Similar to Bubble Sort, the space complexity for Comb Sort is constant -- O(1). This is extremely space efficient as it sorts the array in place. From a9c311588b2ecee2420af4cfee91217db427f450 Mon Sep 17 00:00:00 2001 From: Mac Bellingrath Date: Wed, 26 Dec 2018 15:27:08 -0500 Subject: [PATCH 252/327] Update README.md --- Convex Hull/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Convex Hull/README.md b/Convex Hull/README.md index d27027a45..ab263f00d 100644 --- a/Convex Hull/README.md +++ b/Convex Hull/README.md @@ -2,7 +2,7 @@ Given a group of points on a plane. The Convex Hull algorithm calculates the shape (made up from the points itself) containing all these points. It can also be used on a collection of points of different dimensions. This implementation however covers points on a plane. It essentially calculates the lines between points which together contain all points. In comparing different solutions to this problem we can describe each algorithm in terms of it's big-O time complexity. -There are multiple Convex Hull algorithms but this solution is called Quickhull, is comes from the work of both W. Eddy in 1977 and also separately A. Bykat in 1978, this algorithm has an expected time complexity of O(n log n), but it's worst-case time-complexity can be O(n^2) . With average conditions the algorithm has ok efficiency, but it's time-complexity can start to head become more exponential in cases of high symmetry or where there are points lying on the circumference of a circle for example. +There are multiple Convex Hull algorithms but this solution is called Quickhull, is comes from the work of both W. Eddy in 1977 and also separately A. Bykat in 1978, this algorithm has an expected time complexity of O(n log n), but it's worst-case time-complexity can be O(n^2) . With average conditions the algorithm has ok efficiency, but it's time-complexity can start to become more exponential in cases of high symmetry or where there are points lying on the circumference of a circle for example. ## Quickhull From c1b704dfbe27b96a67a34949055bcc55a47ca7c3 Mon Sep 17 00:00:00 2001 From: Mac Bellingrath Date: Thu, 27 Dec 2018 09:14:45 -0500 Subject: [PATCH 253/327] Update README.md --- Convex Hull/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Convex Hull/README.md b/Convex Hull/README.md index d27027a45..71a470f56 100644 --- a/Convex Hull/README.md +++ b/Convex Hull/README.md @@ -17,7 +17,7 @@ The quickhull algorithm works as follows: - Keep on doing so on until no more points are left, the recursion has come to an end and the points selected constitute the convex hull. -Our functioni will have the following defininition: +Our function will have the following defininition: `findHull(points: [CGPoint], p1: CGPoint, p2: CGPoint)` From 611253f617661d54280dd2861dfe57b3e4568b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20C=2E=20Kr=C3=BCger?= Date: Fri, 11 Jan 2019 10:43:51 +0100 Subject: [PATCH 254/327] GCD improvements after review - Default parameter values - umbrella for different gcd implementations with generic gcd(_: _:) function - better structure of readme file including all 3 algorithms --- GCD/GCD.playground/Contents.swift | 154 ++------------------- GCD/{ => GCD.playground/Sources}/GCD.swift | 35 +++-- GCD/README.markdown | 146 ++++++++++++++----- 3 files changed, 151 insertions(+), 184 deletions(-) rename GCD/{ => GCD.playground/Sources}/GCD.swift (73%) diff --git a/GCD/GCD.playground/Contents.swift b/GCD/GCD.playground/Contents.swift index 175d26639..bb8d49055 100644 --- a/GCD/GCD.playground/Contents.swift +++ b/GCD/GCD.playground/Contents.swift @@ -1,147 +1,21 @@ -//: Playground - noun: a place where people can play +gcd(52, 39) // 13 +gcd(228, 36) // 12 +gcd(51357, 3819) // 57 +gcd(841, 299) // 1 -/* - Iterative approach based on the Euclidean algorithm. - The Euclidean algorithm is based on the principle that the greatest - common divisor of two numbers does not change if the larger number - is replaced by its difference with the smaller number. - - Parameter m: First natural number - - Parameter n: Second natural number - - Returns: The natural gcd if m and n - */ -func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { - var a: Int = 0 - var b: Int = max(m, n) - var r: Int = min(m, n) - - while r != 0 { - a = b - b = r - r = a % b - } - return b -} - -/* - Recursive approach based on the Euclidean algorithm. - - - Parameter m: First natural number - - Parameter n: Second natural number - - Returns: The natural gcd of m and n - - Note: The recursive version makes only tail recursive calls. - Most compilers for imperative languages do not optimize these. - The swift compiler as well as the obj-c compiler is able to do - optimizations for tail recursive calls, even though it still ends - up to be the same in terms of complexity. That said, tail call - elimination is not mutually exclusive to recursion. - */ -func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { - let r: Int = m % n - if r != 0 { - return gcdRecursiveEuklid(n, r) - } else { - return n - } -} - -/* - The binary GCD algorithm, also known as Stein's algorithm, - is an algorithm that computes the greatest common divisor of two - nonnegative integers. Stein's algorithm uses simpler arithmetic - operations than the conventional Euclidean algorithm; it replaces - division with arithmetic shifts, comparisons, and subtraction. - - - Parameter m: First natural number - - Parameter n: Second natural number - - Returns: The natural gcd of m and n - - Complexity: worst case O(n^2), where n is the number of bits - in the larger of the two numbers. Although each step reduces - at least one of the operands by at least a factor of 2, - the subtract and shift operations take linear time for very - large integers - */ -func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { - if let easySolution = findEasySolution(m, n) { return easySolution } - - if (m & 1) == 0 { - // m is even - if (n & 1) == 1 { - // and n is odd - return gcdBinaryRecursiveStein(m >> 1, n) - } else { - // both m and n are even - return gcdBinaryRecursiveStein(m >> 1, n >> 1) << 1 - } - } else if (n & 1) == 0 { - // m is odd, n is even - return gcdBinaryRecursiveStein(m, n >> 1) - } else if (m > n) { - // reduce larger argument - return gcdBinaryRecursiveStein((m - n) >> 1, n) - } else { - // reduce larger argument - return gcdBinaryRecursiveStein((n - m) >> 1, m) - } -} - -/* - Finds an easy solution for the gcd. - - Note: It might be relevant for different usecases to - try finding an easy solution for the GCD calculation - before even starting more difficult operations. - */ -func findEasySolution(_ m: Int, _ n: Int) -> Int? { - if m == n { - return m - } - if m == 0 { - return n - } - if n == 0 { - return m - } - return nil -} - - -enum LCMError: Error { - case divisionByZero -} - -/* - Calculates the lcm for two given numbers using a specified gcd algorithm. - - - Parameter m: First natural number. - - Parameter n: Second natural number. - - Parameter using: The used gcd algorithm to calculate the lcm. - - Throws: Can throw a `divisionByZero` error if one of the given - attributes turns out to be zero or less. - - Returns: The least common multiplier of the two attributes as - an unsigned integer - */ -func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { - guard (m & n) != 0 else { throw LCMError.divisionByZero } - return m / gcdAlgorithm(m, n) * n -} - -gcdIterativeEuklid(52, 39) // 13 -gcdIterativeEuklid(228, 36) // 12 -gcdIterativeEuklid(51357, 3819) // 57 -gcdIterativeEuklid(841, 299) // 1 - -gcdRecursiveEuklid(52, 39) // 13 -gcdRecursiveEuklid(228, 36) // 12 -gcdRecursiveEuklid(51357, 3819) // 57 -gcdRecursiveEuklid(841, 299) // 1 +gcd(52, 39, using: gcdRecursiveEuklid) // 13 +gcd(228, 36, using: gcdRecursiveEuklid) // 12 +gcd(51357, 3819, using: gcdRecursiveEuklid) // 57 +gcd(841, 299, using: gcdRecursiveEuklid) // 1 -gcdBinaryRecursiveStein(52, 39) // 13 -gcdBinaryRecursiveStein(228, 36) // 12 -gcdBinaryRecursiveStein(51357, 3819) // 57 -gcdBinaryRecursiveStein(841, 299) // 1 +gcd(52, 39, using: gcdBinaryRecursiveStein) // 13 +gcd(228, 36, using: gcdBinaryRecursiveStein) // 12 +gcd(51357, 3819, using: gcdBinaryRecursiveStein) // 57 +gcd(841, 299, using: gcdBinaryRecursiveStein) // 1 do { - try lcm(2, 3, using: gcdIterativeEuklid) // 6 - try lcm(10, 8, using: gcdIterativeEuklid) // 40 + try lcm(2, 3) // 6 + try lcm(10, 8, using: gcdRecursiveEuklid) // 40 } catch { dump(error) } diff --git a/GCD/GCD.swift b/GCD/GCD.playground/Sources/GCD.swift similarity index 73% rename from GCD/GCD.swift rename to GCD/GCD.playground/Sources/GCD.swift index f4b390e63..4eb0c7621 100644 --- a/GCD/GCD.swift +++ b/GCD/GCD.playground/Sources/GCD.swift @@ -1,3 +1,17 @@ +/* + Finds the largest positive integer that divides both + m and n without a remainder. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Parameter using: The used algorithm to calculate the gcd. + If nothing provided, the Iterative Euclidean + algorithm is used. + - Returns: The natural gcd of m and n. + */ +public func gcd(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int) = gcdIterativeEuklid) -> Int { + return gcdAlgorithm(m, n) +} /* Iterative approach based on the Euclidean algorithm. @@ -6,9 +20,9 @@ is replaced by its difference with the smaller number. - Parameter m: First natural number - Parameter n: Second natural number - - Returns: The natural gcd if m and n + - Returns: The natural gcd of m and n. */ -func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { +public func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { var a: Int = 0 var b: Int = max(m, n) var r: Int = min(m, n) @@ -26,7 +40,7 @@ func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { - Parameter m: First natural number - Parameter n: Second natural number - - Returns: The natural gcd of m and n + - Returns: The natural gcd of m and n. - Note: The recursive version makes only tail recursive calls. Most compilers for imperative languages do not optimize these. The swift compiler as well as the obj-c compiler is able to do @@ -34,7 +48,7 @@ func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { up to be the same in terms of complexity. That said, tail call elimination is not mutually exclusive to recursion. */ -func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { +public func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { let r: Int = m % n if r != 0 { return gcdRecursiveEuklid(n, r) @@ -59,7 +73,7 @@ func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { the subtract and shift operations take linear time for very large integers */ -func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { +public func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { if let easySolution = findEasySolution(m, n) { return easySolution } if (m & 1) == 0 { @@ -85,6 +99,9 @@ func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { /* Finds an easy solution for the gcd. + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: A natural gcd of m and n if possible. - Note: It might be relevant for different usecases to try finding an easy solution for the GCD calculation before even starting more difficult operations. @@ -103,7 +120,7 @@ func findEasySolution(_ m: Int, _ n: Int) -> Int? { } -enum LCMError: Error { +public enum LCMError: Error { case divisionByZero } @@ -113,12 +130,14 @@ enum LCMError: Error { - Parameter m: First natural number. - Parameter n: Second natural number. - Parameter using: The used gcd algorithm to calculate the lcm. + If nothing provided, the Iterative Euclidean + algorithm is used. - Throws: Can throw a `divisionByZero` error if one of the given attributes turns out to be zero or less. - Returns: The least common multiplier of the two attributes as an unsigned integer */ -func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { - guard (m & n) != 0 else { throw LCMError.divisionByZero } +public func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int) = gcdIterativeEuklid) throws -> Int { + guard m & n != 0 else { throw LCMError.divisionByZero } return m / gcdAlgorithm(m, n) * n } diff --git a/GCD/README.markdown b/GCD/README.markdown index a23aea190..07a3f0f4d 100644 --- a/GCD/README.markdown +++ b/GCD/README.markdown @@ -1,14 +1,19 @@ # Greatest Common Divisor The *greatest common divisor* (or Greatest Common Factor) of two numbers `a` and `b` is the largest positive integer that divides both `a` and `b` without a remainder. The GCD.swift file contains three different algorithms of how to calculate the greatest common divisor. +For example, `gcd(39, 52) = 13` because 13 divides 39 (`39 / 13 = 3`) as well as 52 (`52 / 13 = 4`). But there is no larger number than 13 that divides them both. +You've probably had to learn about this in school at some point. :-) -For example, `gcdIterativeEuklid(39, 52) = 13` because 13 divides 39 (`39/13 = 3`) as well as 52 (`52/13 = 4`). But there is no larger number than 13 that divides them both. +You probably won't need to use the GCD or LCM in any real-world problems, but it's cool to play around with this ancient algorithm. It was first described by Euklid in his [Elements](http://publicdomainreview.org/collections/the-first-six-books-of-the-elements-of-euclid-1847/) around 300 BC. Rumor has it that he discovered this algorithm while he was hacking on his Commodore 64. -You've probably had to learn about this in school at some point. :-) +## Different Algorithms -The laborious way to find the GCD of two numbers is to first figure out the factors of both numbers, then take the greatest number they have in common. The problem is that factoring numbers is quite difficult, especially when they get larger. (On the plus side, that difficulty is also what keeps your online payments secure.) +This example includes three different algorithms to find the same result. -There is a smarter way to calculate the GCD: Euclid's algorithm. The big idea here is that, +### Iterative Euklidean + +The laborious way to find the GCD of two numbers is to first figure out the factors of both numbers, then take the greatest number they have in common. The problem is that factoring numbers is quite difficult, especially when they get larger. (On the plus side, that difficulty is also what keeps your online payments secure.) +There is a smarter way to calculate the GCD: Euklid's algorithm. The big idea here is that, gcd(a, b) = gcd(b, a % b) @@ -16,6 +21,33 @@ where `a % b` calculates the remainder of `a` divided by `b`. Here is an implementation of this idea in Swift: +```swift +func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { + var a: Int = 0 + var b: Int = max(m, n) + var r: Int = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } + return b +} +``` + +Put it in a playground and try it out with these examples: + +```swift +gcd(52, 39, using: gcdIterativeEuklid) // 13 +gcd(228, 36, using: gcdIterativeEuklid) // 12 +gcd(51357, 3819, using: gcdIterativeEuklid) // 57 +``` + +### Recursive Euklidean + +Here is a slightly different implementation of Euklid's algorithm. Unlike the first version this doesn't use a `while` loop, but leverages recursion. + ```swift func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { let r: Int = m % n @@ -27,19 +59,21 @@ func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { } ``` -Put it in a playground and try it out with these examples: +Put it in a playground and compare it with the results of the iterative Eulidean gcd. They should return the same results: ```swift -gcdBinaryRecursiveStein(52, 39) // 13 -gcdRecursiveEuklid(228, 36) // 12 -gcdIterativeEuklid(51357, 3819) // 57 +gcd(52, 39, using: gcdRecursiveEuklid) // 13 +gcd(228, 36, using: gcdRecursiveEuklid) // 12 +gcd(51357, 3819, using: gcdRecursiveEuklid) // 57 ``` -Let's step through the third example using gcd as a representation of the gcdRecursiveEuklid here: +The `max()` and `min()` at the top of the function make sure we always divide the larger number by the smaller one. + +Let's step through the third example using the *recursive Euklidean algorithm* here: gcd(51357, 3819) -According to Euclid's rule, this is equivalent to, +According to Euklid's rule, this is equivalent to, gcd(3819, 51357 % 3819) = gcd(3819, 1710) @@ -57,7 +91,7 @@ And now can't divide any further. The remainder of `114 / 57` is zero because `1 gcd(3819, 51357) = gcd(57, 0) = 57 -So in each step of Euclid's algorithm the numbers become smaller and at some point it ends when one of them becomes zero. +So in each step of Euklid's algorithm the numbers become smaller and at some point it ends when one of them becomes zero. By the way, it's also possible that two numbers have a GCD of 1. They are said to be *relatively prime*. This happens when there is no number that divides them both, for example: @@ -65,55 +99,95 @@ By the way, it's also possible that two numbers have a GCD of 1. They are said t gcd(841, 299) // 1 ``` -Here is a slightly different implementation of Euclid's algorithm. Unlike the first version this doesn't use recursion but only a basic `while` loop. +### Binary Recursive Stein + +The binary GCD algorithm, also known as Stein's algorithm, is an algorithm that computes the greatest common divisor of two nonnegative integers. Stein's algorithm is very similar to the recursive Eulidean algorithm, but uses arithmetical operations, which are simpler for computers to perform, than the conventional Euclidean algorithm does. It replaces division with arithmetic shifts, comparisons, and subtraction. ```swift -func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { - var a: Int = 0 - var b: Int = max(m, n) - var r: Int = min(m, n) +func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { + if let easySolution = findEasySolution(m, n) { return easySolution } + + if (m & 1) == 0 { + // m is even + if (n & 1) == 1 { + // and n is odd + return gcdBinaryRecursiveStein(m >> 1, n) + } else { + // both m and n are even + return gcdBinaryRecursiveStein(m >> 1, n >> 1) << 1 + } + } else if (n & 1) == 0 { + // m is odd, n is even + return gcdBinaryRecursiveStein(m, n >> 1) + } else if (m > n) { + // reduce larger argument + return gcdBinaryRecursiveStein((m - n) >> 1, n) + } else { + // reduce larger argument + return gcdBinaryRecursiveStein((n - m) >> 1, m) + } +} +``` - while r != 0 { - a = b - b = r - r = a % b +Depending on your application and your input expectations, it might be reasonable to also search for an "easy solution" using the other gcd implementations: + +```swift +func findEasySolution(_ m: Int, _ n: Int) -> Int? { + if m == n { + return m } - return b + if m == 0 { + return n + } + if n == 0 { + return m + } + return nil } + ``` -The `max()` and `min()` at the top of the function make sure we always divide the larger number by the smaller one. +Put it in a playground and compare it with the results of the other gcd implementations: + +```swift +gcd(52, 39, using: gcdBinaryRecursiveStein) // 13 +gcd(228, 36, using: gcdBinaryRecursiveStein) // 12 +gcd(51357, 3819, using: gcdBinaryRecursiveStein) // 57 +``` -## Least Common Multiple +### Least Common Multiple -An idea related to the GCD is the *least common multiple* or LCM. +Another algorithm related to the GCD is the *least common multiple* or LCM. -The least common multiple of two numbers `a` and `b` is the smallest positive integer that is a multiple of both. In other words, the LCM is evenly divisible by `a` and `b`. The example implementation of the LCM takes two numbers and a specification which GCD algorithm is used. +The least common multiple of two numbers `a` and `b` is the smallest positive integer that is a multiple of both. In other words, the LCM is evenly divisible by `a` and `b`. The example implementation of the LCM takes two numbers and an optional specification which GCD algorithm is used. -For example: `lcm(2, 3, using: gcdIterativeEuklid) = 6` because 6 can be divided by 2 and also by 3. +For example: `lcm(2, 3, using: gcdRecursiveEuklid) = 6` , which tells us that 6 is the smallest number that can be devided by 2 as well as 3. -We can calculate the LCM using Euclid's algorithm too: +We can calculate the LCM using Euklid's algorithm too: - a * b - lcm(a, b) = --------- - gcd(a, b) +a * b +lcm(a, b) = --------- +gcd(a, b) In code: ```swift -func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { - guard (m & n) != 0 else { throw LCMError.divisionByZero } - return m / gcdAlgorithm(m, n) * n +func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int) = gcdIterativeEuklid) throws -> Int { +guard (m & n) != 0 else { throw LCMError.divisionByZero } +return m / gcdAlgorithm(m, n) * n } ``` And to try it out in a playground: ```swift -lcm(10, 8, using: gcdIterativeEuklid) // 40 +lcm(10, 8) // 40 ``` -You probably won't need to use the GCD or LCM in any real-world problems, but it's cool to play around with this ancient algorithm. It was first described by Euclid in his [Elements](http://publicdomainreview.org/collections/the-first-six-books-of-the-elements-of-euclid-1847/) around 300 BC. Rumor has it that he discovered this algorithm while he was hacking on his Commodore 64. +## Discussion + +While these algorithms all calculate the same result, comparing their plane complexity might not be enough to decide for one of them, though. The original iterative Euklidean algorithm is easier to understand. The recursive Euklidean and Stein's algorithm, while being generally faster, their runtime is heavily dependend on the environment they are running on. +_If a fast calculation of the gcd is necessary, a runtime comparison for the specific platform and compiler optimization level should be done for the rekursive Euklidean and Stein's algorithm._ *Written for Swift Algorithm Club by Matthijs Hollemans* -*Extended by Simon Krüger* \ No newline at end of file +*Extended by Simon C. Krüger* From 15f27793c56cd27788576deb0ef2c8ed901385d2 Mon Sep 17 00:00:00 2001 From: cr0ss Date: Fri, 11 Jan 2019 10:51:27 +0100 Subject: [PATCH 255/327] Linebreak in README --- GCD/README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/GCD/README.markdown b/GCD/README.markdown index 07a3f0f4d..4c459eff0 100644 --- a/GCD/README.markdown +++ b/GCD/README.markdown @@ -190,4 +190,5 @@ While these algorithms all calculate the same result, comparing their plane comp _If a fast calculation of the gcd is necessary, a runtime comparison for the specific platform and compiler optimization level should be done for the rekursive Euklidean and Stein's algorithm._ *Written for Swift Algorithm Club by Matthijs Hollemans* + *Extended by Simon C. Krüger* From c5ff4084bd0f42ef7106a3139c217454aca28015 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Tue, 15 Jan 2019 15:27:38 -0800 Subject: [PATCH 256/327] Fix typo in Stack playground --- Stack/Stack.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index 13774d7d1..e0632f8b4 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -45,7 +45,7 @@ public struct Stack { } /** - Removes and returns the item at the top of the sack. + Removes and returns the item at the top of the stack. - Returns: The item at the top of the stack. */ From 0f2e9e1ebc22de221f508504c6e10bd34a76d919 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 28 Jan 2019 07:57:44 +0100 Subject: [PATCH 257/327] Update hyperlinks Link to author profiles were missing --- AVL Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index e7515d99f..4e974ba71 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -88,4 +88,4 @@ The interesting bits are in the `balance()` method which is called after inserti AVL tree was the first self-balancing binary tree. These days, the [red-black tree](../Red-Black%20Tree/) seems to be more popular. -*Written for Swift Algorithm Club by Mike Taghavi and Matthijs Hollemans* +*Written for Swift Algorithm Club by [Mike Taghavi](https://github.com/mitghi) and [Matthijs Hollemans](https://github.com/hollance)* From ff780b6ff7d25b2aa79cbeef5ac72de6ce76b77e Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Wed, 30 Jan 2019 17:16:49 -0800 Subject: [PATCH 258/327] Update README Updated supported Xcode version to 10 and swift version to 4.2 --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index ff8bfe778..88ea35949 100644 --- a/README.markdown +++ b/README.markdown @@ -8,7 +8,7 @@ If you're a computer science student who needs to learn this stuff for exams -- The goal of this project is to **explain how algorithms work**. The focus is on clarity and readability of the code, not on making a reusable library that you can drop into your own projects. That said, most of the code should be ready for production use but you may need to tweak it to fit into your own codebase. -Code is compatible with **Xcode 9** and **Swift 4**. We'll keep this updated with the latest version of Swift. +Code is compatible with **Xcode 10** and **Swift 4.2**. We'll keep this updated with the latest version of Swift. :heart_eyes: **Suggestions and contributions are welcome!** :heart_eyes: From fa656f090ec4de0b7c9e8bd8eeb2e808c3d7f32c Mon Sep 17 00:00:00 2001 From: Andriy Makukha Date: Fri, 1 Feb 2019 10:20:10 +0800 Subject: [PATCH 259/327] reserveCapacity was missing in README (11% faster with it) --- Merge Sort/README.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Merge Sort/README.markdown b/Merge Sort/README.markdown index 7ad6fd95e..d86f062f4 100644 --- a/Merge Sort/README.markdown +++ b/Merge Sort/README.markdown @@ -79,6 +79,7 @@ func merge(leftPile: [Int], rightPile: [Int]) -> [Int] { // 2 var orderedPile = [Int]() + orderedPile.reserveCapacity(leftPile.count + rightPile.count) // 3 while leftIndex < leftPile.count && rightIndex < rightPile.count { @@ -115,7 +116,7 @@ This method may look scary, but it is quite straightforward: 1. You need two indexes to keep track of your progress for the two arrays while merging. -2. This is the merged array. It is empty right now, but you will build it up in subsequent steps by appending elements from the other arrays. +2. This is the merged array. It is empty right now, but you will build it up in subsequent steps by appending elements from the other arrays. Since you already know number of elements that will end up in this array, you reserve capacity to avoid reallocation overhead later. 3. This while-loop will compare the elements from the left and right sides and append them into the `orderedPile` while making sure that the result stays in order. From d4b9091af6f83f55e9681a5a11b6374bd2ac8cff Mon Sep 17 00:00:00 2001 From: Morgan Davison Date: Sun, 3 Feb 2019 20:45:28 -0500 Subject: [PATCH 260/327] Check with Xcode 10.1 No changes needed --- 3Sum and 4Sum/3Sum.playground/Contents.swift | 4 ++++ .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3Sum and 4Sum/4Sum.playground/Contents.swift | 5 +++++ .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 6 files changed, 39 insertions(+) create mode 100644 3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/3Sum and 4Sum/3Sum.playground/Contents.swift b/3Sum and 4Sum/3Sum.playground/Contents.swift index 2581da6e7..d172aed1f 100644 --- a/3Sum and 4Sum/3Sum.playground/Contents.swift +++ b/3Sum and 4Sum/3Sum.playground/Contents.swift @@ -1,3 +1,7 @@ +// last checked with Xcode 10.1 +#if swift(>=4.2) +print("Hello, Swift 4.2!") +#endif extension Collection where Element: Equatable { diff --git a/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/3Sum and 4Sum/4Sum.playground/Contents.swift b/3Sum and 4Sum/4Sum.playground/Contents.swift index 86b530224..37f75918c 100644 --- a/3Sum and 4Sum/4Sum.playground/Contents.swift +++ b/3Sum and 4Sum/4Sum.playground/Contents.swift @@ -1,3 +1,8 @@ +// last checked with Xcode 10.1 +#if swift(>=4.2) +print("Hello, Swift 4.2!") +#endif + extension Collection where Element: Equatable { /// In a sorted collection, replaces the given index with a successor mapping to a unique element. diff --git a/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 2f92aef01b0d7e6b57e4ae8a9de79467dd7598d9 Mon Sep 17 00:00:00 2001 From: Morgan Kan Date: Wed, 6 Feb 2019 21:34:53 +0000 Subject: [PATCH 261/327] fix bracket formatting --- Bit Set/BitSet.playground/Contents.swift | 14 +++++++------- Bit Set/BitSet.playground/Sources/BitSet.swift | 8 ++++---- Bit Set/BitSet.swift | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index 2c5edcd84..70d5ca5e8 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -93,8 +93,8 @@ z.all1() // false var smallBitSet = BitSet(size: 16) smallBitSet[5] = true smallBitSet[10] = true -print( smallBitSet >> 3 ) -print( smallBitSet << 6 ) // one bit shifts off the end +print(smallBitSet >> 3) +print(smallBitSet << 6) // one bit shifts off the end var bigBitSet = BitSet( size: 120 ) bigBitSet[1] = true @@ -104,8 +104,8 @@ bigBitSet[32] = true bigBitSet[55] = true bigBitSet[64] = true bigBitSet[80] = true -print( bigBitSet ) -print( bigBitSet << 32 ) -print( bigBitSet << 64 ) -print( bigBitSet >> 32 ) -print( bigBitSet >> 64 ) +print(bigBitSet) +print(bigBitSet << 32) +print(bigBitSet << 64) +print(bigBitSet >> 32) +print(bigBitSet >> 64) diff --git a/Bit Set/BitSet.playground/Sources/BitSet.swift b/Bit Set/BitSet.playground/Sources/BitSet.swift index 85f5da505..258bce457 100644 --- a/Bit Set/BitSet.playground/Sources/BitSet.swift +++ b/Bit Set/BitSet.playground/Sources/BitSet.swift @@ -235,10 +235,10 @@ public func << (lhs: BitSet, numBitsLeft: Int) -> BitSet { let shift = numBitsLeft % lhs.N for i in 0..= 0 ) { + if (i - offset >= 0) { out.words[i] = lhs.words[i - offset] << shift } - if( i - offset - 1 >= 0 ) { + if (i - offset - 1 >= 0) { out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) } } @@ -253,10 +253,10 @@ public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { let shift = numBitsRight % lhs.N for i in 0..> shift } - if( i + offset + 1 < lhs.words.count ) { + if (i + offset + 1 < lhs.words.count) { out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) } } diff --git a/Bit Set/BitSet.swift b/Bit Set/BitSet.swift index 83829c6c5..19413f424 100644 --- a/Bit Set/BitSet.swift +++ b/Bit Set/BitSet.swift @@ -235,10 +235,10 @@ public func << (lhs: BitSet, numBitsLeft: Int) -> BitSet { let shift = numBitsLeft % lhs.N for i in 0..= 0 ) { + if (i - offset >= 0) { out.words[i] = lhs.words[i - offset] << shift } - if( i - offset - 1 >= 0 ) { + if (i - offset - 1 >= 0) { out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) } } @@ -253,10 +253,10 @@ public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { let shift = numBitsRight % lhs.N for i in 0..> shift } - if( i + offset + 1 < lhs.words.count ) { + if (i + offset + 1 < lhs.words.count) { out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) } } From 27efddaa9ceaa4f1675dc69433d253ce028596f1 Mon Sep 17 00:00:00 2001 From: Larissa Laich Date: Thu, 7 Feb 2019 20:47:01 +0100 Subject: [PATCH 262/327] fixed error in linear regression formula --- Linear Regression/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index 4f9d030db..db04bf8a2 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -75,7 +75,7 @@ for _ in 1...numberOfIterations { The program loops through each data point (each car age and car price). For each data point it adjusts the intercept and the slope to bring them closer to the correct values. The equations used in the code to adjust the intercept and the slope are based on moving in the direction of the maximal reduction of these variables. This is a *gradient descent*. -We want to minimise the square of the distance between the line and the points. We define a function `J` which represents this distance - for simplicity we consider only one point here. This function `J` is proportional to `((slope.carAge + intercept) - carPrice)) ^ 2`. +We want to minimise the square of the distance between the line and the points. We define a function `J` which represents this distance - for simplicity we consider only one point here. This function `J` is proportional to `((slope * carAge + intercept) - carPrice)) ^ 2`. In order to move in the direction of maximal reduction, we take the partial derivative of this function with respect to the slope, and similarly for the intercept. We multiply these derivatives by our factor alpha and then use them to adjust the values of slope and intercept on each iteration. From 6d936e461435783e2a19afcf6b817e1b9c0ceb5f Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Tue, 12 Feb 2019 14:38:02 +0530 Subject: [PATCH 263/327] Update Karatsuba README --- Karatsuba Multiplication/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown index aef0d744a..02e54a1bf 100644 --- a/Karatsuba Multiplication/README.markdown +++ b/Karatsuba Multiplication/README.markdown @@ -115,10 +115,10 @@ What about the running time of this algorithm? Is all this extra work worth it? ## Resources -[Wikipedia] (https://en.wikipedia.org/wiki/Karatsuba_algorithm) +[Wikipedia](https://en.wikipedia.org/wiki/Karatsuba_algorithm) -[WolframMathWorld] (http://mathworld.wolfram.com/KaratsubaMultiplication.html) +[WolframMathWorld](http://mathworld.wolfram.com/KaratsubaMultiplication.html) -[Master Theorem] (https://en.wikipedia.org/wiki/Master_theorem) +[Master Theorem](https://en.wikipedia.org/wiki/Master_theorem) *Written for Swift Algorithm Club by Richard Ash* From deae79c2010d1e7341b24314819c9736cdfc4387 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Tue, 12 Feb 2019 15:07:50 +0530 Subject: [PATCH 264/327] Update README Replace "minimise" with "minimize" --- Linear Regression/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index db04bf8a2..d07bf1497 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -21,7 +21,7 @@ Let's start by looking at the data plotted out: We could imagine a straight line drawn through the points on this graph. It's not (in this case) going to go exactly through every point, but we could place the line so that it goes as close to all the points as possible. -To say this in another way, we want to make the distance from the line to each point as small as possible. This is most often done by minimising the square of the distance from the line to each point. +To say this in another way, we want to make the distance from the line to each point as small as possible. This is most often done by minimizing the square of the distance from the line to each point. We can describe the straight line in terms of two variables: @@ -75,7 +75,7 @@ for _ in 1...numberOfIterations { The program loops through each data point (each car age and car price). For each data point it adjusts the intercept and the slope to bring them closer to the correct values. The equations used in the code to adjust the intercept and the slope are based on moving in the direction of the maximal reduction of these variables. This is a *gradient descent*. -We want to minimise the square of the distance between the line and the points. We define a function `J` which represents this distance - for simplicity we consider only one point here. This function `J` is proportional to `((slope * carAge + intercept) - carPrice)) ^ 2`. +We want to minimize the square of the distance between the line and the points. We define a function `J` which represents this distance - for simplicity we consider only one point here. This function `J` is proportional to `((slope * carAge + intercept) - carPrice)) ^ 2`. In order to move in the direction of maximal reduction, we take the partial derivative of this function with respect to the slope, and similarly for the intercept. We multiply these derivatives by our factor alpha and then use them to adjust the values of slope and intercept on each iteration. From a88c984a388c456de27302af796180bf25b15529 Mon Sep 17 00:00:00 2001 From: Morgan Kan Date: Fri, 15 Feb 2019 18:19:58 +0000 Subject: [PATCH 265/327] remove duplicate source file, update README --- Bit Set/BitSet.swift | 293 ---------------------------------------- Bit Set/README.markdown | 84 ++++++++++++ 2 files changed, 84 insertions(+), 293 deletions(-) delete mode 100644 Bit Set/BitSet.swift diff --git a/Bit Set/BitSet.swift b/Bit Set/BitSet.swift deleted file mode 100644 index 19413f424..000000000 --- a/Bit Set/BitSet.swift +++ /dev/null @@ -1,293 +0,0 @@ -/* - A fixed-size sequence of n bits. Bits have indices 0 to n-1. - */ -public struct BitSet { - /* How many bits this object can hold. */ - private(set) public var size: Int - - /* - We store the bits in a list of unsigned 64-bit integers. - The first entry, `words[0]`, is the least significant word. - */ - fileprivate let N = 64 - public typealias Word = UInt64 - fileprivate(set) public var words: [Word] - - private let allOnes = ~Word() - - /* Creates a bit set that can hold `size` bits. All bits are initially 0. */ - public init(size: Int) { - precondition(size > 0) - self.size = size - - // Round up the count to the next multiple of 64. - let n = (size + (N-1)) / N - words = [Word](repeating: 0, count: n) - } - - /* Converts a bit index into an array index and a mask inside the word. */ - private func indexOf(_ i: Int) -> (Int, Word) { - precondition(i >= 0) - precondition(i < size) - let o = i / N - let m = Word(i - o*N) - return (o, 1 << m) - } - - /* Returns a mask that has 1s for all bits that are in the last word. */ - private func lastWordMask() -> Word { - let diff = words.count*N - size - if diff > 0 { - // Set the highest bit that's still valid. - let mask = 1 << Word(63 - diff) - // Subtract 1 to turn it into a mask, and add the high bit back in. - return (Word)(mask | (mask - 1)) - } else { - return allOnes - } - } - - /* - If the size is not a multiple of N, then we have to clear out the bits - that we're not using, or bitwise operations between two differently sized - BitSets will go wrong. - */ - fileprivate mutating func clearUnusedBits() { - words[words.count - 1] &= lastWordMask() - } - - /* So you can write bitset[99] = ... */ - public subscript(i: Int) -> Bool { - get { return isSet(i) } - set { if newValue { set(i) } else { clear(i) } } - } - - /* Sets the bit at the specified index to 1. */ - public mutating func set(_ i: Int) { - let (j, m) = indexOf(i) - words[j] |= m - } - - /* Sets all the bits to 1. */ - public mutating func setAll() { - for i in 0.. Bool { - let (j, m) = indexOf(i) - words[j] ^= m - return (words[j] & m) != 0 - } - - /* Determines whether the bit at the specific index is 1 (true) or 0 (false). */ - public func isSet(_ i: Int) -> Bool { - let (j, m) = indexOf(i) - return (words[j] & m) != 0 - } - - /* - Returns the number of bits that are 1. Time complexity is O(s) where s is - the number of 1-bits. - */ - public var cardinality: Int { - var count = 0 - for var x in words { - while x != 0 { - let y = x & ~(x - 1) // find lowest 1-bit - x = x ^ y // and erase it - count += 1 - } - } - return count - } - - /* Checks if all the bits are set. */ - public func all1() -> Bool { - for i in 0.. Bool { - for x in words { - if x != 0 { return true } - } - return false - } - - /* Checks if none of the bits are set. */ - public func all0() -> Bool { - for x in words { - if x != 0 { return false } - } - return true - } -} - -// MARK: - Equality - -extension BitSet: Equatable { -} - -public func == (lhs: BitSet, rhs: BitSet) -> Bool { - return lhs.words == rhs.words -} - -// MARK: - Hashing - -extension BitSet: Hashable { - /* Based on the hashing code from Java's BitSet. */ - public var hashValue: Int { - var h = Word(1234) - for i in stride(from: words.count, to: 0, by: -1) { - h ^= words[i - 1] &* Word(i) - } - return Int((h >> 32) ^ h) - } -} - -// MARK: - Bitwise operations - -extension BitSet { - public static var allZeros: BitSet { - return BitSet(size: 64) - } -} - -private func copyLargest(_ lhs: BitSet, _ rhs: BitSet) -> BitSet { - return (lhs.words.count > rhs.words.count) ? lhs : rhs -} - -/* - Note: In all of these bitwise operations, lhs and rhs are allowed to have a - different number of bits. The new BitSet always has the larger size. - The extra bits that get added to the smaller BitSet are considered to be 0. - That will strip off the higher bits from the larger BitSet when doing &. - */ - -public func & (lhs: BitSet, rhs: BitSet) -> BitSet { - let m = max(lhs.size, rhs.size) - var out = BitSet(size: m) - let n = min(lhs.words.count, rhs.words.count) - for i in 0.. BitSet { - var out = copyLargest(lhs, rhs) - let n = min(lhs.words.count, rhs.words.count) - for i in 0.. BitSet { - var out = copyLargest(lhs, rhs) - let n = min(lhs.words.count, rhs.words.count) - for i in 0.. BitSet { - var out = BitSet(size: rhs.size) - for i in 0.. BitSet { - var out = lhs - let offset = numBitsLeft / lhs.N - let shift = numBitsLeft % lhs.N - for i in 0..= 0) { - out.words[i] = lhs.words[i - offset] << shift - } - if (i - offset - 1 >= 0) { - out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) - } - } - - out.clearUnusedBits() - return out -} - -public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { - var out = lhs - let offset = numBitsRight / lhs.N - let shift = numBitsRight % lhs.N - for i in 0..> shift - } - if (i + offset + 1 < lhs.words.count) { - out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) - } - } - - out.clearUnusedBits() - return out -} - - -// MARK: - Debugging - -extension UInt64 { - /* Writes the bits in little-endian order, LSB first. */ - public func bitsToString() -> String { - var s = "" - var n = self - for _ in 1...64 { - s += ((n & 1 == 1) ? "1" : "0") - n >>= 1 - } - return s - } -} - -extension BitSet: CustomStringConvertible { - public var description: String { - var s = "" - for x in words { - s += x.bitsToString() + " " - } - return s - } -} - diff --git a/Bit Set/README.markdown b/Bit Set/README.markdown index 6bb6e7c89..365950d06 100644 --- a/Bit Set/README.markdown +++ b/Bit Set/README.markdown @@ -329,6 +329,90 @@ This is the original value but with the lowest 1-bit removed. We keep repeating this process until the value consists of all zeros. The time complexity is **O(s)** where **s** is the number of 1-bits. +## Bit Shift Operations + +Bit shifts are a common and very useful mechanism when dealing with bitsets. Here is the right-shift function: + +``` +public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { + var out = lhs + let offset = numBitsRight / lhs.N + let shift = numBitsRight % lhs.N + for i in 0..> shift + } + + if (i + offset + 1 < lhs.words.count) { + out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} +``` + +Let's start with this line: + +```swift +for i in 0..> 10 + +I've grouped each part of the number by word to make it easier to see what happens. The for-loop goes from least significant word to most significant. So for index zero we're want to know what bits will make up our least significant word. Let's calculate our offset and shift values: + + offset = 10 / 8 = 1 (remember this is integer division) + shift = 10 % 8 = 2 + +So we consult the word at offset 1 to get some of our bits: + + 11000000 >> 2 = 00110000 + +And we get the rest of them from the word one further away: + + 01000010 << (8 - 2) = 10000000 + +And we bitwise OR these together to get our least significant term + + 00110000 + 10000000 + -------- OR + 10110000 + +We repeat this for the 2nd least significant term and obtain: + + 00010000 + +The last term can't get any bits because they are past the end of our number so those are all zeros. Our result is: + + 00000000 00010000 10110000 + ## See also [Bit Twiddling Hacks](http://graphics.stanford.edu/~seander/bithacks.html) From a10a15bab9934520d1762b5a71f357e6b112bc2a Mon Sep 17 00:00:00 2001 From: Morgan Kan Date: Sat, 16 Feb 2019 09:49:47 +0000 Subject: [PATCH 266/327] remove reference to old source file --- swift-algorithm-club.xcworkspace/contents.xcworkspacedata | 3 --- 1 file changed, 3 deletions(-) diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index a37dac494..12be3d827 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -549,9 +549,6 @@ - - From aa2a318bfbf24223a26a609d8a23dba3accba935 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Sun, 24 Feb 2019 14:53:47 -0800 Subject: [PATCH 267/327] [Swift 4.2] Update All-Pairs Shortest Paths to Swift 4.2 --- .../APSP/APSP.playground/Contents.swift | 5 ---- .../APSP.playground/contents.xcplayground | 2 +- .../APSP/APSP.xcodeproj/project.pbxproj | 26 ++++++++++++++----- .../xcshareddata/xcschemes/APSP.xcscheme | 2 +- .../xcshareddata/xcschemes/APSPTests.xcscheme | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++ .../APSP/APSPTests/APSPTests.swift | 8 ------ .../xcshareddata/xcschemes/Graph.xcscheme | 2 +- .../xcschemes/GraphTests.xcscheme | 2 +- 9 files changed, 33 insertions(+), 24 deletions(-) create mode 100644 All-Pairs Shortest Paths/APSP/APSP.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift b/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift index b1b499b39..24c27cac8 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift +++ b/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Graph import APSP diff --git a/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground b/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground index 06828af92..d5a8d0e3f 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground +++ b/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj index 908d32785..dc8e509a1 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj @@ -187,12 +187,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 493D8DDF1CDD2A1C0089795A = { CreatedOnToolsVersion = 7.3; - LastSwiftMigration = 0820; + LastSwiftMigration = 1010; }; 493D8DF01CDD5B960089795A = { CreatedOnToolsVersion = 7.3; @@ -302,14 +302,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -349,14 +357,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -388,7 +404,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -400,7 +416,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -420,7 +436,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -443,7 +458,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme index e313c4b88..944957d8f 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme @@ -1,6 +1,6 @@ + + + + IDEDidComputeMac32BitWarning + + + diff --git a/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift b/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift index c2f64e239..ce0dfcf32 100644 --- a/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift +++ b/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift @@ -19,14 +19,6 @@ struct TestCase where T: Hashable { } class APSPTests: XCTestCase { - - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } - /** See Figure 25.1 of “Introduction to Algorithms” by Cormen et al, 3rd ed., pg 690 */ diff --git a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme index 73524effc..84c688e66 100644 --- a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme +++ b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 25 Feb 2019 22:08:56 +0900 Subject: [PATCH 268/327] Fix wrong description Signed-off-by: bbvch13531 --- Linked List/LinkedList.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 7c2cbb3b1..de8a42c93 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -67,7 +67,7 @@ public final class LinkedList { /// - Returns: LinkedListNode public func node(at index: Int) -> Node { assert(head != nil, "List is empty") - assert(index >= 0, "index must be greater than 0") + assert(index >= 0, "index must be greater or equal to 0") if index == 0 { return head! From 8a6d99aa19f0888b51969bc10c0463aa98c1a94e Mon Sep 17 00:00:00 2001 From: bbvch13531 Date: Mon, 25 Feb 2019 22:09:44 +0900 Subject: [PATCH 269/327] Fix typo Signed-off-by: bbvch13531 --- Insertion Sort/InsertionSort.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Insertion Sort/InsertionSort.swift b/Insertion Sort/InsertionSort.swift index 9faf9dc42..2ad607ac8 100644 --- a/Insertion Sort/InsertionSort.swift +++ b/Insertion Sort/InsertionSort.swift @@ -22,7 +22,7 @@ func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { /// Performs the Insertion sort algorithm to a given array /// -/// - Parameter array: the array to be sorted, conatining elements that conform to the Comparable protocol +/// - Parameter array: the array to be sorted, containing elements that conform to the Comparable protocol /// - Returns: a sorted array containing the same elements func insertionSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } From de935b700ab32492791dbd9771a3fc841ad4044c Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 5 Mar 2019 22:37:29 -0500 Subject: [PATCH 270/327] Updates README.markdown * now using new `random` API from the Swift collection protocols, instead of creating a new function that uses `arc4random` * updates code to Swift 4.2 * fixes some inconsistencies between terms begin used - such as `MAX_GENERATIONS` and `GENERATIONS` --- Genetic/README.markdown | 60 ++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index 18afb9639..5dc4747f2 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -5,7 +5,7 @@ A genetic algorithm (GA) is process inspired by natural selection to find high quality solutions. Most commonly used for optimization. GAs rely on the bio-inspired processes of natural selection, more specifically the process of selection (fitness), crossover and mutation. To understand more, let's walk through these processes in terms of biology: ### Selection ->**Selection**, in biology, the preferential survival and reproduction or preferential elimination of individuals with certain genotypes (genetic compositions), by means of natural or artificial controlling factors. [Britannica](britannica) +>**Selection**, in biology, the preferential survival and reproduction or preferential elimination of individuals with certain genotypes (genetic compositions), by means of natural or artificial controlling factors. In other words, survival of the fittest. Organisms that survive in their environment tend to reproduce more. With GAs we generate a fitness model that will rank individuals and give them a better chance for reproduction. @@ -60,35 +60,23 @@ extension String { let OPTIMAL:[UInt8] = "Hello, World".unicodeArray let DNA_SIZE = OPTIMAL.count let POP_SIZE = 50 -let MAX_GENERATIONS = 5000 +let GENERATIONS = 5000 let MUTATION_CHANCE = 100 ``` - The last piece we need for set up is a function to give us a random unicode value from our lexicon: - - ```swift - func randomChar(from lexicon: [UInt8]) -> UInt8 { - let len = UInt32(lexicon.count-1) - let rand = Int(arc4random_uniform(len)) - return lexicon[rand] - } - ``` - - **Note**: `arc4random_uniform` is strictly used in this example. It would be fun to play around with some of the [randomization in GameKit](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html) - ### Population Zero Before selecting, crossover and mutation, we need a population to start with. Now that we have the universe defined we can write that function: ```swift func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { - + guard lexicon.count > 1 else { return [] } var pop = [[UInt8]]() (0.. Int { +func calculateFitness(dna: [UInt8], optimal: [UInt8]) -> Int { + guard dna.count == optimal.count else { return -1 } var fitness = 0 - (0...dna.count-1).forEach { c in - fitness += abs(Int(dna[c]) - Int(optimal[c])) + for index in dna.indices { + fitness += abs(Int(dna[index]) - Int(optimal[index])) } return fitness } @@ -121,13 +110,11 @@ Let's take a second and ask why on this one. Why would you not always want to se With all that, here is our weight choice function: -```swift -func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { - - let total = items.reduce(0.0) { return $0 + $1.weight} - - var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 - +func weightedChoice(items: [(dna: [UInt8], weight: Double)]) -> (dna: [UInt8], weight: Double) { + + let total = items.reduce(0) { $0 + $1.weight } + var n = Double.random(in: 0..<(total * 1000000)) / 1000000.0 + for item in items { if n < item.weight { return item @@ -136,25 +123,24 @@ func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weigh } return items[1] } -``` -The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. The horrible 1,000,000 multiplication and division is to insure precision by calculating decimals. `arc4random` only uses integers so this is required to convert to a precise Double, it's not perfect, but enough for our example. + +The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. The horrible 1,000,000 multiplication and division is to insure precision by calculating decimals. `Double.random` only uses integers so this is required to convert to a precise Double, it's not perfect, but enough for our example. ## Mutation The all powerful mutation, the thing that introduces otherwise non existent fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achieve the optimal solution. ```swift -func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { +func mutate(lexicon: [UInt8], dna: [UInt8], mutationChance: Int) -> [UInt8] { var outputDna = dna - (0.. [UInt8] { - let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) - +func crossover(dna1: [UInt8], dna2: [UInt8], dnaSize: Int) -> [UInt8] { + let pos = Int.random(in: 0.. Date: Tue, 5 Mar 2019 22:38:53 -0500 Subject: [PATCH 271/327] Updates code to Swift 4.2 --- Genetic/gen.playground/Contents.swift | 192 +++++++++++--------------- 1 file changed, 84 insertions(+), 108 deletions(-) diff --git a/Genetic/gen.playground/Contents.swift b/Genetic/gen.playground/Contents.swift index 79a398ceb..d76342f56 100644 --- a/Genetic/gen.playground/Contents.swift +++ b/Genetic/gen.playground/Contents.swift @@ -1,14 +1,12 @@ -//: Playground - noun: a place where people can play -import Foundation extension String { - var unicodeArray: [UInt8] { - return [UInt8](self.utf8) - } + + var unicodeArray: [UInt8] { + return [UInt8](self.utf8) + } } - let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".unicodeArray // This is the end goal and what we will be using to rate fitness. In the real world this will not exist @@ -17,132 +15,110 @@ let OPTIMAL:[UInt8] = "Hello, World".unicodeArray // The length of the string in our population. Organisms need to be similar let DNA_SIZE = OPTIMAL.count -// size of each generation +// Size of each generation let POP_SIZE = 50 -// max number of generations, script will stop when it reach 5000 if the optimal value is not found +// Max number of generations, script will stop when it reaches 5000 if the optimal value is not found let GENERATIONS = 5000 // The chance in which a random nucleotide can mutate (1/n) let MUTATION_CHANCE = 100 -func randomChar(from lexicon: [UInt8]) -> UInt8 { - let len = UInt32(lexicon.count-1) - let rand = Int(arc4random_uniform(len)) - return lexicon[rand] -} - func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { - - var pop = [[UInt8]]() - - (0.. Int { - var fitness = 0 - (0...dna.count-1).forEach { c in - fitness += abs(Int(dna[c]) - Int(optimal[c])) - } - return fitness +func calculateFitness(dna: [UInt8], optimal: [UInt8]) -> Int { + var fitness = 0 + for index in dna.indices { + fitness += abs(Int(dna[index]) - Int(optimal[index])) + } + return fitness } -func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { - - let total = items.reduce(0.0) { return $0 + $1.weight} - - var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 - - for item in items { - if n < item.weight { - return item - } - n = n - item.weight +func weightedChoice(items: [(dna: [UInt8], weight: Double)]) -> (dna: [UInt8], weight: Double) { + + let total = items.reduce(0) { $0 + $1.weight } + var n = Double.random(in: 0..<(total * 1000000)) / 1000000.0 + + for item in items { + if n < item.weight { + return item } - return items[1] + n = n - item.weight + } + return items[1] } -func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { - var outputDna = dna - - (0.. [UInt8] { + var outputDna = dna + (0.. [UInt8] { - let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) - - let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) - let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) - - return [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)) +func crossover(dna1: [UInt8], dna2: [UInt8], dnaSize: Int) -> [UInt8] { + let pos = Int.random(in: 0.. Date: Tue, 5 Mar 2019 22:46:10 -0500 Subject: [PATCH 272/327] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 88ea35949..064a4616c 100644 --- a/README.markdown +++ b/README.markdown @@ -100,7 +100,7 @@ Bad sorting algorithms (don't use these!): - [Convex Hull](Convex%20Hull/). - [Miller-Rabin Primality Test](Miller-Rabin%20Primality%20Test/). Is the number a prime number? - [MinimumCoinChange](MinimumCoinChange/). A showcase for dynamic programming. - +- [Genetic](Genetic/). A simple example on how to slowly mutate a value to its ideal form, in the context of biological evolution. ### Mathematics - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. From 04b2d3010b3db16b1bfd472e9686364bbf785a94 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Fri, 8 Mar 2019 23:13:13 -0500 Subject: [PATCH 273/327] Updates for Swift 5.0 Removes unnecessary equatable implementations, since default implementations of `Equatable` has identical result. --- .../Points Lines Planes/2D/Line2D.swift | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/Points Lines Planes/Points Lines Planes/2D/Line2D.swift b/Points Lines Planes/Points Lines Planes/2D/Line2D.swift index c92cbdbed..c23040b14 100644 --- a/Points Lines Planes/Points Lines Planes/2D/Line2D.swift +++ b/Points Lines Planes/Points Lines Planes/2D/Line2D.swift @@ -14,27 +14,11 @@ struct Line2D: Equatable { enum Slope: Equatable { case finite(slope: Double) case infinite(offset: Double) - - static func ==(lhs: Slope, rhs: Slope) -> Bool { - switch (lhs, rhs) { - case (.finite(let slope1), .finite(let slope2)): return slope1 == slope2 - case (.infinite(let offset1), .infinite(let offset2)): return offset1 == offset2 - default: return false - } - } } enum Direction: Equatable { case increasing case decreasing - - static func ==(lhs: Direction, rhs: Direction) -> Bool { - switch (lhs, rhs) { - case (.increasing, .increasing): return true - case (.decreasing, .decreasing): return true - default: return false - } - } } init(from p1: Point2D, to p2: Point2D) { @@ -154,8 +138,4 @@ struct Line2D: Equatable { return Line2D(slope: .finite(slope: 0), offset: p.y, direction: dir) } } - - static func ==(lhs: Line2D, rhs: Line2D) -> Bool { - return lhs.slope == rhs.slope && lhs.offset == rhs.offset && lhs.direction == rhs.direction - } } From 339cc1489b3b70e7464db4af7e8f398d45ce50db Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Fri, 8 Mar 2019 23:13:42 -0500 Subject: [PATCH 274/327] Updates to Swift 5.0 Removes `Equatable` impl. --- Points Lines Planes/Points Lines Planes/2D/Point2D.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Points Lines Planes/Points Lines Planes/2D/Point2D.swift b/Points Lines Planes/Points Lines Planes/2D/Point2D.swift index f51ffd64d..bbd8305f8 100644 --- a/Points Lines Planes/Points Lines Planes/2D/Point2D.swift +++ b/Points Lines Planes/Points Lines Planes/2D/Point2D.swift @@ -9,10 +9,6 @@ struct Point2D: Equatable { var x: Double var y: Double - static func ==(lhs: Point2D, rhs: Point2D) -> Bool { - return lhs.x == rhs.x && lhs.y == rhs.y - } - // returns true if point is on or right of line func isRight(of line: Line2D) -> Bool { switch line.slope { From 5e55f9261bc4095df3424fdd9f238513e0eae8e5 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 9 Mar 2019 19:39:32 -0500 Subject: [PATCH 275/327] Adds Myers Difference Algorithm to Readme --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 064a4616c..97917a320 100644 --- a/README.markdown +++ b/README.markdown @@ -101,6 +101,7 @@ Bad sorting algorithms (don't use these!): - [Miller-Rabin Primality Test](Miller-Rabin%20Primality%20Test/). Is the number a prime number? - [MinimumCoinChange](MinimumCoinChange/). A showcase for dynamic programming. - [Genetic](Genetic/). A simple example on how to slowly mutate a value to its ideal form, in the context of biological evolution. +- [Myers Difference Algorithm](Myers\ Difference\ Algorithm/). Finding the longest common subsequence of two sequences. ### Mathematics - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. From 46c22ac590f580268a5c1fce288f6f8a720b37bb Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 9 Mar 2019 19:40:06 -0500 Subject: [PATCH 276/327] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 97917a320..c94716242 100644 --- a/README.markdown +++ b/README.markdown @@ -101,7 +101,7 @@ Bad sorting algorithms (don't use these!): - [Miller-Rabin Primality Test](Miller-Rabin%20Primality%20Test/). Is the number a prime number? - [MinimumCoinChange](MinimumCoinChange/). A showcase for dynamic programming. - [Genetic](Genetic/). A simple example on how to slowly mutate a value to its ideal form, in the context of biological evolution. -- [Myers Difference Algorithm](Myers\ Difference\ Algorithm/). Finding the longest common subsequence of two sequences. +- [Myers Difference Algorithm](Myers Difference Algorithm/). Finding the longest common subsequence of two sequences. ### Mathematics - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. From 3849a1d6113ddb7d8ac24be2a1e9fc4b7677efd6 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 9 Mar 2019 19:41:21 -0500 Subject: [PATCH 277/327] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index c94716242..d66eee5d8 100644 --- a/README.markdown +++ b/README.markdown @@ -101,7 +101,7 @@ Bad sorting algorithms (don't use these!): - [Miller-Rabin Primality Test](Miller-Rabin%20Primality%20Test/). Is the number a prime number? - [MinimumCoinChange](MinimumCoinChange/). A showcase for dynamic programming. - [Genetic](Genetic/). A simple example on how to slowly mutate a value to its ideal form, in the context of biological evolution. -- [Myers Difference Algorithm](Myers Difference Algorithm/). Finding the longest common subsequence of two sequences. +- [Myers Difference Algorithm](Myers%20Difference%20Algorithm/). Finding the longest common subsequence of two sequences. ### Mathematics - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. From 0d5e1b94e49311607fc0b30cc379304fe2123798 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 14 Mar 2019 22:44:36 -0400 Subject: [PATCH 278/327] Update README.markdown Adds a reference to the GitHub page via #720 --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index d66eee5d8..44879e8f8 100644 --- a/README.markdown +++ b/README.markdown @@ -8,7 +8,7 @@ If you're a computer science student who needs to learn this stuff for exams -- The goal of this project is to **explain how algorithms work**. The focus is on clarity and readability of the code, not on making a reusable library that you can drop into your own projects. That said, most of the code should be ready for production use but you may need to tweak it to fit into your own codebase. -Code is compatible with **Xcode 10** and **Swift 4.2**. We'll keep this updated with the latest version of Swift. +Code is compatible with **Xcode 10** and **Swift 4.2**. We'll keep this updated with the latest version of Swift. If you're interested in a GitHub pages version of the repo, check out [this](https://aquarchitect.github.io/swift-algorithm-club/). :heart_eyes: **Suggestions and contributions are welcome!** :heart_eyes: From 56e2fc9047a4523d62d3f1fe4eac679b20382509 Mon Sep 17 00:00:00 2001 From: bbvch13531 Date: Fri, 15 Mar 2019 19:52:09 +0900 Subject: [PATCH 279/327] Change return type to brief type. Fixes :#865 Signed-off-by: bbvch13531 --- .../Sources/BinarySearchTree.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift index 34ade3896..2d0eb7e57 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift @@ -235,7 +235,7 @@ extension BinarySearchTree { /* Finds the node whose value precedes our value in sorted order. */ - public func predecessor() -> BinarySearchTree? { + public func predecessor() -> BinarySearchTree? { if let left = left { return left.maximum() } else { @@ -251,7 +251,7 @@ extension BinarySearchTree { /* Finds the node whose value succeeds our value in sorted order. */ - public func successor() -> BinarySearchTree? { + public func successor() -> BinarySearchTree? { if let right = right { return right.minimum() } else { From 7065c1a2d0aa0633188cdb27de69c11ab8d740d5 Mon Sep 17 00:00:00 2001 From: Dmitry Cherednikov Date: Sat, 16 Mar 2019 15:44:00 +0400 Subject: [PATCH 280/327] Implement getPredecessor(). --- Red-Black Tree/README.markdown | 1 + .../Sources/RedBlackTree.swift | 27 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Red-Black Tree/README.markdown b/Red-Black Tree/README.markdown index fd6c4db18..352588056 100644 --- a/Red-Black Tree/README.markdown +++ b/Red-Black Tree/README.markdown @@ -29,6 +29,7 @@ From [CLRS] ## Methods Nodes: +* `nodeX.getPredecessor()` Returns the inorder predecessor of nodeX * `nodeX.getSuccessor()` Returns the inorder successor of nodeX * `nodeX.minimum()` Returns the node with the minimum key of the subtree of nodeX * `nodeX.maximum()` Returns the node with the maximum key of the subtree of nodeX diff --git a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift index 59633031d..b88cd7cf5 100644 --- a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift +++ b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift @@ -60,6 +60,10 @@ public class RBTreeNode: Equatable { self.init(key: nil, leftChild: nil, rightChild: nil, parent: nil) self.color = .black } + + public func getKey() -> T? { + return key + } var isRoot: Bool { return parent == nil @@ -120,9 +124,30 @@ extension RBTreeNode { } } -// MARK: - Finding a nodes successor +// MARK: - Finding a nodes successor and predecessor extension RBTreeNode { + /* + * Returns the inorder predecessor node of a node + * The predecessor is a node with the next smaller key value of the current node + */ + public func getPredecessor() -> RBNode? { + // if node has left child: predecessor is min of this left tree + if let leftChild = leftChild, !leftChild.isNullLeaf { + return leftChild.maximum() + } + // else go upward while node is left child + var currentNode = self + var parent = currentNode.parent + while currentNode.isLeftChild { + if let parent = parent { + currentNode = parent + } + parent = currentNode.parent + } + return parent + } + /* * Returns the inorder successor node of a node * The successor is a node with the next larger key value of the current node From 6e8b5cdc37324a4120abee841d89cef36ab6352f Mon Sep 17 00:00:00 2001 From: TL Date: Wed, 20 Mar 2019 16:09:34 +0800 Subject: [PATCH 281/327] Update Shuffle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit according to https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle `checks if j ≠ i may be omitted`, and also remove checking logic will optimise performance(tested by 100000 times random). --- Shuffle/README.markdown | 3 --- Shuffle/Shuffle.swift | 3 --- 2 files changed, 6 deletions(-) diff --git a/Shuffle/README.markdown b/Shuffle/README.markdown index 63868767b..d8ab7ff78 100644 --- a/Shuffle/README.markdown +++ b/Shuffle/README.markdown @@ -96,9 +96,6 @@ public func shuffledArray(_ n: Int) -> [Int] { var a = [Int](repeating: 0, count: n) for i in 0.. [Int] { var a = Array(repeating: 0, count: n) for i in 0.. Date: Thu, 21 Mar 2019 10:17:06 -0400 Subject: [PATCH 282/327] Update SlowSort.swift --- Slow Sort/SlowSort.swift | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index bd8288b18..546a36395 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -7,14 +7,14 @@ // func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - guard if i < j else { return } - let m = (i+j)/2 - slowSort(i, m, &numberList) - slowSort(m+1, j, &numberList) - if numberList[j] < numberList[m] { - let temp = numberList[j] - numberList[j] = numberList[m] - numberList[m] = temp - } - slowSort(i, j-1, &numberList) + guard if i < j else { return } + let m = (i+j)/2 + slowSort(i, m, &numberList) + slowSort(m+1, j, &numberList) + if numberList[j] < numberList[m] { + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp + } + slowSort(i, j-1, &numberList) } From 7457ceb7e9ec688ac11db158ac3d32118df49b0f Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 21 Mar 2019 10:25:04 -0400 Subject: [PATCH 283/327] Two-spaced indents --- Comb Sort/Tests/CombSortTests.swift | 32 ++++++++++++----------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/Comb Sort/Tests/CombSortTests.swift b/Comb Sort/Tests/CombSortTests.swift index 166065484..1d83af002 100644 --- a/Comb Sort/Tests/CombSortTests.swift +++ b/Comb Sort/Tests/CombSortTests.swift @@ -9,26 +9,20 @@ import XCTest class CombSortTests: XCTestCase { - var sequence: [Int]! - let expectedSequence: [Int] = [-12, -10, -1, 2, 9, 32, 55, 67, 89, 101] - - func testSwiftVersion(){ - #if swift(>=4.2) - print("Hello, Swift 4.2!") - #endif - } + var sequence: [Int]! + let expectedSequence: [Int] = [-12, -10, -1, 2, 9, 32, 55, 67, 89, 101] - override func setUp() { - super.setUp() - sequence = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] - } + override func setUp() { + super.setUp() + sequence = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] + } - override func tearDown() { - super.tearDown() - } + override func tearDown() { + super.tearDown() + } - func testCombSort() { - let sortedSequence = combSort(sequence) - XCTAssertEqual(sortedSequence, expectedSequence) - } + func testCombSort() { + let sortedSequence = combSort(sequence) + XCTAssertEqual(sortedSequence, expectedSequence) + } } From fdab1a2d7a9f9797ed7be27c5023f284c47f38ea Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 21 Mar 2019 10:25:24 -0400 Subject: [PATCH 284/327] two spaced indents --- Slow Sort/SlowSort.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index 546a36395..968f6841b 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -12,9 +12,9 @@ func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { slowSort(i, m, &numberList) slowSort(m+1, j, &numberList) if numberList[j] < numberList[m] { - let temp = numberList[j] - numberList[j] = numberList[m] - numberList[m] = temp + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp } slowSort(i, j-1, &numberList) } From 7405c64e2cf7c035dce15207bba0fe7434010b55 Mon Sep 17 00:00:00 2001 From: Priyanka- Date: Sun, 24 Mar 2019 12:20:31 -0700 Subject: [PATCH 285/327] Kth Largest Element: updated to use Int.random API which has been introduced with Swift 4.2 --- .../kthLargest.playground/Sources/kthLargest.swift | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift b/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift index 397c43a38..aad15eac6 100644 --- a/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift +++ b/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift @@ -16,12 +16,6 @@ public func kthLargest(_ a: [Int], _ k: Int) -> Int? { // MARK: - Randomized selection -/* Returns a random integer in the range min...max, inclusive. */ -public func random(min: Int, max: Int) -> Int { - assert(min < max) - return min + Int(arc4random_uniform(UInt32(max - min + 1))) -} - /* Returns the i-th smallest element from the array. @@ -39,7 +33,7 @@ public func randomizedSelect(_ array: [T], order k: Int) -> T { var a = array func randomPivot(_ a: inout [T], _ low: Int, _ high: Int) -> T { - let pivotIndex = random(min: low, max: high) + let pivotIndex = Int.random(in: low...high) a.swapAt(pivotIndex, high) return a[high] } From b6e9a40652d489605772f284ad2dac4a033fd216 Mon Sep 17 00:00:00 2001 From: TL Date: Tue, 26 Mar 2019 15:34:12 +0800 Subject: [PATCH 286/327] Update Shuffle --- Shuffle/README.markdown | 4 ++++ Shuffle/Shuffle.swift | 1 + 2 files changed, 5 insertions(+) diff --git a/Shuffle/README.markdown b/Shuffle/README.markdown index d8ab7ff78..5a2a07a98 100644 --- a/Shuffle/README.markdown +++ b/Shuffle/README.markdown @@ -96,6 +96,8 @@ public func shuffledArray(_ n: Int) -> [Int] { var a = [Int](repeating: 0, count: n) for i in 0.. [Int] { var a = Array(repeating: 0, count: n) for i in 0.. Date: Sun, 28 Apr 2019 13:19:59 -0400 Subject: [PATCH 287/327] Adds Closest Pair --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 44879e8f8..3e0174576 100644 --- a/README.markdown +++ b/README.markdown @@ -208,6 +208,7 @@ A lot of software developer interview questions consist of algorithmic puzzles. - [Dining Philosophers](DiningPhilosophers/) - [Egg Drop Problem](Egg%20Drop%20Problem/) - [Encoding and Decoding Binary Tree](Encode%20and%20Decode%20Tree/) +- [Closest Pair](Closest%20Pair/) ## Learn more! From 721af5d569661effa976e88fc65a14fd3961b826 Mon Sep 17 00:00:00 2001 From: Vladislav Badulin Date: Mon, 29 Apr 2019 21:24:24 +0200 Subject: [PATCH 288/327] This fixes the unlikely event that the generated hashValue happens to be the equal to Int.min, in which case the abs value of it would be Int.max + 1 causing overflow. --- Hash Table/HashTable.playground/Sources/HashTable.swift | 2 +- Hash Table/README.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Hash Table/HashTable.playground/Sources/HashTable.swift b/Hash Table/HashTable.playground/Sources/HashTable.swift index 476a51174..f2a1be040 100644 --- a/Hash Table/HashTable.playground/Sources/HashTable.swift +++ b/Hash Table/HashTable.playground/Sources/HashTable.swift @@ -131,7 +131,7 @@ public struct HashTable { Returns the given key's array index. */ private func index(forKey key: Key) -> Int { - return abs(key.hashValue) % buckets.count + return abs(key.hashValue % buckets.count) } } diff --git a/Hash Table/README.markdown b/Hash Table/README.markdown index 9c4065a51..fb0bda788 100644 --- a/Hash Table/README.markdown +++ b/Hash Table/README.markdown @@ -141,7 +141,7 @@ The hash table does not do anything yet, so let's add the remaining functionalit ```swift private func index(forKey key: Key) -> Int { - return abs(key.hashValue) % buckets.count + return abs(key.hashValue % buckets.count) } ``` From 15db2b6d953d1130acb711a358a79f5237979d02 Mon Sep 17 00:00:00 2001 From: Vanderlei Alves <39912609+vzanshin@users.noreply.github.com> Date: Fri, 3 May 2019 15:47:53 -0300 Subject: [PATCH 289/327] Fix typo and grammar --- .github/CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e5d00c17b..29f4ca7e1 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -6,7 +6,7 @@ Want to help out with the Swift Algorithm Club? Great! While we don't have stric Our repo is all about learning. The `README` file is the cake, and the sample code is the cherry on top. A good contribution has succinct explanations supported by diagrams. Code is best introduced in chunks, weaved into the explanations where relevant. -> When choosing between brievity and performance, err to the side of brievity as long as the time complexity of the particular implementation is the same. You can make a note afterwards suggesting a more performant way of doing things. +> When choosing between brevity and performance, err to the side of brevity as long as the time complexity of the particular implementation is the same. You can make a note afterwards suggesting a more performant way of doing things. **API Design Guidelines** @@ -22,7 +22,7 @@ We follow the following Swift [style guide](https://github.com/raywenderlich/swi Unit tests. Fixes for typos. No contribution is too small. :-) -The repository has over 100 different data structures and algorithms. We're always interested in improvements to existing implementations and better explanations. Suggestions for making the code more Swift-like or to make it fit better with the standard library is most welcomed. +The repository has over 100 different data structures and algorithms. We're always interested in improvements to existing implementations and better explanations. Suggestions for making the code more Swift-like or to make it fit better with the standard library are most welcome. ### New Contributions From 3f1d661b2d95eb0349d824277447c63c0aa3ecf1 Mon Sep 17 00:00:00 2001 From: Vanderlei Alves <39912609+vzanshin@users.noreply.github.com> Date: Wed, 8 May 2019 16:39:15 -0300 Subject: [PATCH 290/327] Fix minor typo at Heap/README --- Heap/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heap/README.markdown b/Heap/README.markdown index 76d2bee39..6c65fe9c8 100755 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -29,7 +29,7 @@ As a result of this heap property, a max-heap always stores its largest item at ## How does a heap compare to regular trees? -A heap is not a replacement for a binary search tree, and there are similarities and differnces between them. Here are some main differences: +A heap is not a replacement for a binary search tree, and there are similarities and differences between them. Here are some main differences: **Order of the nodes.** In a [binary search tree (BST)](../Binary%20Search%20Tree/), the left child must be smaller than its parent, and the right child must be greater. This is not true for a heap. In a max-heap both children must be smaller than the parent, while in a min-heap they both must be greater. From 78a7ceeff6c59a740428c6fae41a79f660c5a58c Mon Sep 17 00:00:00 2001 From: Kenny Schlagel Date: Sun, 7 Jul 2019 19:52:11 -0600 Subject: [PATCH 291/327] Improvements to Count Occurrences --- .../Contents.swift | 20 +++++++-------- Count Occurrences/CountOccurrences.swift | 25 ++++++++++--------- Count Occurrences/README.markdown | 12 ++++----- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/Count Occurrences/CountOccurrences.playground/Contents.swift b/Count Occurrences/CountOccurrences.playground/Contents.swift index a34e3485f..6ab4c00f3 100644 --- a/Count Occurrences/CountOccurrences.playground/Contents.swift +++ b/Count Occurrences/CountOccurrences.playground/Contents.swift @@ -1,11 +1,11 @@ -func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { - func leftBoundary() -> Int { +func countOccurrences(of key: T, in array: [T]) -> Int { + var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] < key { + if array[midIndex] < key { low = midIndex + 1 } else { high = midIndex @@ -14,12 +14,12 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - func rightBoundary() -> Int { + var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] > key { + if array[midIndex] > key { high = midIndex } else { low = midIndex + 1 @@ -28,13 +28,13 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - return rightBoundary() - leftBoundary() + return rightBoundary - leftBoundary } // Simple test let a = [ 0, 1, 1, 3, 3, 3, 3, 6, 8, 10, 11, 11 ] -countOccurrencesOfKey(3, inArray: a) +countOccurrences(of: 3, in: a) // Test with arrays of random size and contents (see debug output) @@ -59,6 +59,6 @@ for _ in 0..<10 { // Note: we also test -1 and 6 to check the edge cases. for k in -1...6 { - print("\t\(k): \(countOccurrencesOfKey(k, inArray: a))") + print("\t\(k): \(countOccurrences(of: k, in: a))") } } diff --git a/Count Occurrences/CountOccurrences.swift b/Count Occurrences/CountOccurrences.swift index 10dd12c4f..532e3810e 100644 --- a/Count Occurrences/CountOccurrences.swift +++ b/Count Occurrences/CountOccurrences.swift @@ -1,14 +1,15 @@ -/* - Counts the number of times a value appears in an array in O(lg n) time. - The array must be sorted from low to high. -*/ -func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { - func leftBoundary() -> Int { +/// Counts the number of times a value appears in an array in O(log n) time. The array must be sorted from low to high. +/// +/// - Parameter key: the key to be searched for in the array +/// - Parameter array: the array to search +/// - Returns: the count of occurences of the key in the given array +func countOccurrences(of key: T, in array: [T]) -> Int { + var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] < key { + if array[midIndex] < key { low = midIndex + 1 } else { high = midIndex @@ -17,12 +18,12 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - func rightBoundary() -> Int { + var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] > key { + if array[midIndex] > key { high = midIndex } else { low = midIndex + 1 @@ -31,5 +32,5 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - return rightBoundary() - leftBoundary() + return rightBoundary - leftBoundary } diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 85b77d2d0..297bc4b0f 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -22,8 +22,8 @@ The trick is to use two binary searches, one to find where the `3`s start (the l In code this looks as follows: ```swift -func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { - func leftBoundary() -> Int { +func countOccurrences(of key: T, in array: [T]) -> Int { + var leftBoundary: Int { var low = 0 var high = a.count while low < high { @@ -37,7 +37,7 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - func rightBoundary() -> Int { + var rightBoundary: Int { var low = 0 var high = a.count while low < high { @@ -51,11 +51,11 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - return rightBoundary() - leftBoundary() + return rightBoundary - leftBoundary } ``` -Notice that the helper functions `leftBoundary()` and `rightBoundary()` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. +Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an array of Strings, Ints or other types that conform to the Swift Comparable protocol. To test this algorithm, copy the code to a playground and then do: @@ -113,7 +113,7 @@ The right boundary is at index 7. The difference between the two boundaries is 7 Each binary search took 4 steps, so in total this algorithm took 8 steps. Not a big gain on an array of only 12 items, but the bigger the array, the more efficient this algorithm becomes. For a sorted array with 1,000,000 items, it only takes 2 x 20 = 40 steps to count the number of occurrences for any particular value. -By the way, if the value you're looking for is not in the array, then `rightBoundary()` and `leftBoundary()` return the same value and so the difference between them is 0. +By the way, if the value you're looking for is not in the array, then `rightBoundary` and `leftBoundary` return the same value and so the difference between them is 0. This is an example of how you can modify the basic binary search to solve other algorithmic problems as well. Of course, it does require that the array is sorted. From 6e64f07b43971ba04b85887bf3bf2d616243c21a Mon Sep 17 00:00:00 2001 From: ygit Date: Wed, 10 Jul 2019 02:38:29 +0530 Subject: [PATCH 292/327] added Big O computation comparison graph --- Big-O Notation.markdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Big-O Notation.markdown b/Big-O Notation.markdown index 257f80462..9509331a5 100644 --- a/Big-O Notation.markdown +++ b/Big-O Notation.markdown @@ -18,6 +18,11 @@ Big-O | Name | Description **O(n!)** | factorial | **Intolerably slow.** It literally takes a million years to do anything. + +![Comparison of Big O computations](https://upload.wikimedia.org/wikipedia/commons/7/7e/Comparison_computational_complexity.svg) + + + Below are some examples for each category of performance: **O(1)** From 762de527ad71e07f36ca9fd417819d733d298bdd Mon Sep 17 00:00:00 2001 From: markgz Date: Thu, 8 Aug 2019 17:09:28 +0800 Subject: [PATCH 293/327] The code of O(2^n) isn't correct which is O(n) Need solve two smaller problems in one recursive call --- Big-O Notation.markdown | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Big-O Notation.markdown b/Big-O Notation.markdown index 9509331a5..c3f020df2 100644 --- a/Big-O Notation.markdown +++ b/Big-O Notation.markdown @@ -124,9 +124,8 @@ Below are some examples for each category of performance: func solveHanoi(n: Int, from: String, to: String, spare: String) { guard n >= 1 else { return } if n > 1 { - solveHanoi(n: n - 1, from: from, to: spare, spare: to) - } else { - solveHanoi(n: n - 1, from: spare, to: to, spare: from) + solveHanoi(n: n - 1, from: from, to: spare, spare: to) + solveHanoi(n: n - 1, from: spare, to: to, spare: from) } } ``` From dfea1d68dd6151f88221c6be34a0a78002c50537 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 31 Aug 2019 11:12:51 +0500 Subject: [PATCH 294/327] Update Queue-Optimized.swift --- Queue/Queue-Optimized.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Queue/Queue-Optimized.swift b/Queue/Queue-Optimized.swift index 7dff91698..aedf9c67f 100644 --- a/Queue/Queue-Optimized.swift +++ b/Queue/Queue-Optimized.swift @@ -23,7 +23,7 @@ public struct Queue { } public mutating func dequeue() -> T? { - guard head < array.count, let element = array[head] else { return nil } + guard let element = array[guarded: head] else { return nil } array[head] = nil head += 1 @@ -45,3 +45,14 @@ public struct Queue { } } } + +extension Array { + + subscript(guarded idx: Int) -> Element? { + guard (startIndex.. Date: Fri, 6 Sep 2019 11:39:57 +0500 Subject: [PATCH 295/327] Added changed by opened discussions --- Queue/Queue-Optimized.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Queue/Queue-Optimized.swift b/Queue/Queue-Optimized.swift index aedf9c67f..3b17b98cb 100644 --- a/Queue/Queue-Optimized.swift +++ b/Queue/Queue-Optimized.swift @@ -47,12 +47,10 @@ public struct Queue { } extension Array { - subscript(guarded idx: Int) -> Element? { guard (startIndex.. Date: Fri, 6 Sep 2019 13:18:40 -0700 Subject: [PATCH 296/327] Updated broken link Updated link to Boyer-Moore-Horspool algorithm. --- Knuth-Morris-Pratt/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Knuth-Morris-Pratt/README.markdown b/Knuth-Morris-Pratt/README.markdown index 95fdea9e9..2e4d5360b 100644 --- a/Knuth-Morris-Pratt/README.markdown +++ b/Knuth-Morris-Pratt/README.markdown @@ -14,7 +14,7 @@ let concert = "🎼🎹🎹🎸🎸🎻🎻🎷🎺🎤👏👏👏" concert.indexesOf(ptnr: "🎻🎷") // Output: [6] ``` -The [Knuth-Morris-Pratt algorithm](https://en.wikipedia.org/wiki/Knuth–Morris–Pratt_algorithm) is considered one of the best algorithms for solving the pattern matching problem. Although in practice [Boyer-Moore](../Boyer-Moore/) is usually preferred, the algorithm that we will introduce is simpler, and has the same (linear) running time. +The [Knuth-Morris-Pratt algorithm](https://en.wikipedia.org/wiki/Knuth–Morris–Pratt_algorithm) is considered one of the best algorithms for solving the pattern matching problem. Although in practice [Boyer-Moore](../Boyer-Moore-Horspool/) is usually preferred, the algorithm that we will introduce is simpler, and has the same (linear) running time. The idea behind the algorithm is not too different from the [naive string search](../Brute-Force%20String%20Search/) procedure. As it, Knuth-Morris-Pratt aligns the text with the pattern and goes with character comparisons from left to right. But, instead of making a shift of one character when a mismatch occurs, it uses a more intelligent way to move the pattern along the text. In fact, the algorithm features a pattern pre-processing stage where it acquires all the informations that will make the algorithm skip redundant comparisons, resulting in larger shifts. From da2085fc5bd7b08aec0b061301218e90fdf3d35e Mon Sep 17 00:00:00 2001 From: Joe Soultanis Date: Tue, 29 Oct 2019 16:55:50 -0700 Subject: [PATCH 297/327] updaing incorrect big-O performance documentation of heap removal --- Heap/Heap.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heap/Heap.swift b/Heap/Heap.swift index cf39fb8a5..7560bc7b9 100755 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -212,7 +212,7 @@ extension Heap where T: Equatable { return nodes.index(where: { $0 == node }) } - /** Removes the first occurrence of a node from the heap. Performance: O(n log n). */ + /** Removes the first occurrence of a node from the heap. Performance: O(n). */ @discardableResult public mutating func remove(node: T) -> T? { if let index = index(of: node) { return remove(at: index) From 519a57ae2946033608bda0fe24d428e189212df4 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 29 Oct 2019 22:35:24 -0400 Subject: [PATCH 298/327] Removes the workspace. --- .../contents.xcworkspacedata | 2914 ----------------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - 3 files changed, 2930 deletions(-) delete mode 100644 swift-algorithm-club.xcworkspace/contents.xcworkspacedata delete mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 03d06d2f7..000000000 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,2914 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 08de0be8d..000000000 --- a/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded - - - From ed5fca001429674c1f13557a166a19b73e7ba5e0 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Wed, 30 Oct 2019 14:43:34 -0400 Subject: [PATCH 299/327] Removes travis.yml --- .travis.yml | 55 ----------------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 56e205656..000000000 --- a/.travis.yml +++ /dev/null @@ -1,55 +0,0 @@ -language: objective-c -osx_image: xcode9 -# sudo: false - -install: - -- gem install xcpretty-travis-formatter -# - ./install_swiftlint.sh - -script: - -- xcodebuild test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Binary\ Search/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Boyer-Moore-Horspool/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Binary\ Search\ Tree/Solution\ 1/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Bloom\ Filter/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Bounded\ Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Breadth-First\ Search/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Bucket\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./B-Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Comb\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Convex\ Hull/Convex\ Hull.xcodeproj -scheme Tests -destination 'platform=iOS Simulator,name=iPhone 7,OS=11.0' | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Counting\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Depth-First\ Search/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Graph/Graph.xcodeproj -scheme GraphTests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Heap/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Heap\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Insertion\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./K-Means/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Linked\ List/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Singly\ Linked\ List/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Longest\ Common\ Subsequence/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Minimum\ Spanning\ Tree\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Queue/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Quicksort/Tests/Tests-Quicksort.xcodeproj -scheme Test-Quicksort | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Radix\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Rootish\ Array\ Stack/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Select\ Minimum\ Maximum/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Selection\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Shell\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Shortest\ Path\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Single-Source\ Shortest\ Paths\ \(Weighted\)/SSSP.xcodeproj -scheme SSSPTests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Stack/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Treap/Treap/Treap.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Palindromes/Test/Test.xcodeproj -scheme Test | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Ternary\ Search\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Karatsuba\ Multiplication/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` - -after_success: - -- if [[ "$TRAVIS_BRANCH" == "master" ]]; then ./gfm-render.sh; fi From 7b08311b01bb7f4f2a261286e93e9cf7abe6da1b Mon Sep 17 00:00:00 2001 From: Robert Manson Date: Sun, 3 Nov 2019 17:36:22 -0800 Subject: [PATCH 300/327] Fix infinite recursion in DFS Fixes infinite recursion in the DFS algorithm for topological sort caused by graphs with cycles. For example the following graph would previously have recursed indefinitely `a->b->a`. --- Topological Sort/TopologicalSort1.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Topological Sort/TopologicalSort1.swift b/Topological Sort/TopologicalSort1.swift index 2ad9b51a0..05f1ab887 100644 --- a/Topological Sort/TopologicalSort1.swift +++ b/Topological Sort/TopologicalSort1.swift @@ -1,6 +1,7 @@ extension Graph { private func depthFirstSearch(_ source: Node, visited: inout [Node : Bool]) -> [Node] { var result = [Node]() + visited[source] = true if let adjacencyList = adjacencyList(forNode: source) { for nodeInAdjacencyList in adjacencyList { @@ -10,7 +11,6 @@ extension Graph { } } - visited[source] = true return [source] + result } From 0904c23f746bbbbfc5525ce32cf5c181c1eafe8e Mon Sep 17 00:00:00 2001 From: freak4pc Date: Sat, 9 Nov 2019 18:58:19 +0200 Subject: [PATCH 301/327] Use swapAt for Lomuto's partitioning --- Quicksort/Quicksort.playground/Contents.swift | 4 ++-- Quicksort/README.markdown | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Quicksort/Quicksort.playground/Contents.swift b/Quicksort/Quicksort.playground/Contents.swift index 94d9f8e45..bbe5d9b7d 100644 --- a/Quicksort/Quicksort.playground/Contents.swift +++ b/Quicksort/Quicksort.playground/Contents.swift @@ -42,12 +42,12 @@ func partitionLomuto(_ a: inout [T], low: Int, high: Int) -> Int var i = low for j in low..(_ a: inout [T], low: Int, high: Int) -> Int var i = low for j in low.. Date: Wed, 27 Nov 2019 17:22:04 +0800 Subject: [PATCH 302/327] Update Heap.swift Time complexity of remove() is O(n + log n), which simplifies to O(n). --- Heap/Heap.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heap/Heap.swift b/Heap/Heap.swift index cf39fb8a5..7560bc7b9 100755 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -212,7 +212,7 @@ extension Heap where T: Equatable { return nodes.index(where: { $0 == node }) } - /** Removes the first occurrence of a node from the heap. Performance: O(n log n). */ + /** Removes the first occurrence of a node from the heap. Performance: O(n). */ @discardableResult public mutating func remove(node: T) -> T? { if let index = index(of: node) { return remove(at: index) From 7762f6a884daa51e4acdb5677c664bec38273f5c Mon Sep 17 00:00:00 2001 From: TL Date: Fri, 29 Nov 2019 18:52:19 +0800 Subject: [PATCH 303/327] fix: add use case --- Skip-List/SkipList.playground/Contents.swift | 13 +++++++++++++ .../SkipList.playground/Sources/SkipList.swift | 2 +- Skip-List/SkipList.swift | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Skip-List/SkipList.playground/Contents.swift b/Skip-List/SkipList.playground/Contents.swift index 1b4847c0e..55b9d3a23 100644 --- a/Skip-List/SkipList.playground/Contents.swift +++ b/Skip-List/SkipList.playground/Contents.swift @@ -5,3 +5,16 @@ print("Hello, Swift 4!") // SkipList is ready for Swift 4. // TODO: Add Test + +let k = SkipList() +k.insert(key: 10, data: "10") +k.insert(key: 12, data: "12") +k.insert(key: 13, data: "13") +k.insert(key: 20, data: "20") +k.insert(key: 24, data: "24") + +if let value = k.get(key: 20) { + print(value) +} else { + print("not found!") +} diff --git a/Skip-List/SkipList.playground/Sources/SkipList.swift b/Skip-List/SkipList.playground/Sources/SkipList.swift index f626da0f8..186286977 100644 --- a/Skip-List/SkipList.playground/Sources/SkipList.swift +++ b/Skip-List/SkipList.playground/Sources/SkipList.swift @@ -212,7 +212,7 @@ extension SkipList { } } - func insert(key: Key, data: Payload) { + public func insert(key: Key, data: Payload) { if head != nil { if let node = findNode(key: key) { // replace, in case of key already exists. diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift index fc635d0f2..8a1959f70 100644 --- a/Skip-List/SkipList.swift +++ b/Skip-List/SkipList.swift @@ -212,7 +212,7 @@ extension SkipList { } } - func insert(key: Key, data: Payload) { + public func insert(key: Key, data: Payload) { if head != nil { if let node = findNode(key: key) { // replace, in case of key already exists. From b513c0331b79a520cd30569913a624eaae8fa7bb Mon Sep 17 00:00:00 2001 From: Kyle Nicol <54515183+TRGoCPftF@users.noreply.github.com> Date: Tue, 10 Dec 2019 12:30:45 -0500 Subject: [PATCH 304/327] Update simann_example.swift Corrected definition where shuffle() was invoking self.shuffle() instead of self.tour.shuffle(), which would left the example in a infinite loop of shuffle() invocation --- Simulated annealing/simann_example.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Simulated annealing/simann_example.swift b/Simulated annealing/simann_example.swift index 0e07e0024..e7933c89a 100644 --- a/Simulated annealing/simann_example.swift +++ b/Simulated annealing/simann_example.swift @@ -138,7 +138,7 @@ extension Tour { } func shuffle() { - self.shuffle() + self.tour.shuffle() } } From 809cb974dc0b105407500f42e675c55f55e1588b Mon Sep 17 00:00:00 2001 From: "G. Moraleda" Date: Wed, 22 Jan 2020 17:51:05 +0100 Subject: [PATCH 305/327] Typos corrected --- Count Occurrences/README.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 297bc4b0f..95f020e90 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -25,10 +25,10 @@ In code this looks as follows: func countOccurrences(of key: T, in array: [T]) -> Int { var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] < key { + if array[midIndex] < key { low = midIndex + 1 } else { high = midIndex @@ -39,10 +39,10 @@ func countOccurrences(of key: T, in array: [T]) -> Int { var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] > key { + if array[midIndex] > key { high = midIndex } else { low = midIndex + 1 @@ -62,7 +62,7 @@ To test this algorithm, copy the code to a playground and then do: ```swift let a = [ 0, 1, 1, 3, 3, 3, 3, 6, 8, 10, 11, 11 ] -countOccurrencesOfKey(3, inArray: a) // returns 4 +countOccurrences(of: 3, in: a) // returns 4 ``` > **Remember:** If you use your own array, make sure it is sorted first! From 8a7db67f4f0e1706a3a91054f1b7aecc6ac95761 Mon Sep 17 00:00:00 2001 From: "G. Moraleda" Date: Wed, 22 Jan 2020 19:57:53 +0100 Subject: [PATCH 306/327] Update README.markdown --- Count Occurrences/README.markdown | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 95f020e90..2e48d1020 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -22,13 +22,13 @@ The trick is to use two binary searches, one to find where the `3`s start (the l In code this looks as follows: ```swift -func countOccurrences(of key: T, in array: [T]) -> Int { +func countOccurrences(of key: T, in a: [T]) -> Int { var leftBoundary: Int { var low = 0 - var high = array.count + var high = a.count while low < high { let midIndex = low + (high - low)/2 - if array[midIndex] < key { + if a[midIndex] < key { low = midIndex + 1 } else { high = midIndex @@ -39,10 +39,10 @@ func countOccurrences(of key: T, in array: [T]) -> Int { var rightBoundary: Int { var low = 0 - var high = array.count + var high = a.count while low < high { let midIndex = low + (high - low)/2 - if array[midIndex] > key { + if a[midIndex] > key { high = midIndex } else { low = midIndex + 1 @@ -55,7 +55,9 @@ func countOccurrences(of key: T, in array: [T]) -> Int { } ``` -Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an array of Strings, Ints or other types that conform to the Swift Comparable protocol. +Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an + +y of Strings, Ints or other types that conform to the Swift Comparable protocol. To test this algorithm, copy the code to a playground and then do: From 467503c623c0fa781ea337b68a2ee5251d9a20bc Mon Sep 17 00:00:00 2001 From: "G. Moraleda" Date: Wed, 22 Jan 2020 19:58:38 +0100 Subject: [PATCH 307/327] Update README.markdown --- Count Occurrences/README.markdown | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 2e48d1020..4deb9990e 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -55,9 +55,7 @@ func countOccurrences(of key: T, in a: [T]) -> Int { } ``` -Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an - -y of Strings, Ints or other types that conform to the Swift Comparable protocol. +Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an array of Strings, Ints or other types that conform to the Swift Comparable protocol. To test this algorithm, copy the code to a playground and then do: From 43181f5b4c8790fa887c4a6bd5ea8e94b0279eb5 Mon Sep 17 00:00:00 2001 From: Satveer Singh Date: Thu, 6 Feb 2020 19:30:24 +1100 Subject: [PATCH 308/327] Fix typo in Heap Sort README lg -> log --- Heap Sort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heap Sort/README.markdown b/Heap Sort/README.markdown index a45dad6f9..5bec58626 100644 --- a/Heap Sort/README.markdown +++ b/Heap Sort/README.markdown @@ -42,7 +42,7 @@ As you can see, the largest items are making their way to the back. We repeat th > **Note:** This process is very similar to [selection sort](../Selection%20Sort/), which repeatedly looks for the minimum item in the remainder of the array. Extracting the minimum or maximum value is what heaps are good at. -Performance of heap sort is **O(n lg n)** in best, worst, and average case. Because we modify the array directly, heap sort can be performed in-place. But it is not a stable sort: the relative order of identical elements is not preserved. +Performance of heap sort is **O(n log n)** in best, worst, and average case. Because we modify the array directly, heap sort can be performed in-place. But it is not a stable sort: the relative order of identical elements is not preserved. Here's how you can implement heap sort in Swift: From f664af1f502ec7f6692e8dcb34d5848ce3af4e60 Mon Sep 17 00:00:00 2001 From: "G. Moraleda" Date: Mon, 10 Feb 2020 20:01:47 +0100 Subject: [PATCH 309/327] Renamed array --- Count Occurrences/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 4deb9990e..8e935ea58 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -22,10 +22,10 @@ The trick is to use two binary searches, one to find where the `3`s start (the l In code this looks as follows: ```swift -func countOccurrences(of key: T, in a: [T]) -> Int { +func countOccurrences(of key: T, in array: [T]) -> Int { var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 if a[midIndex] < key { @@ -39,7 +39,7 @@ func countOccurrences(of key: T, in a: [T]) -> Int { var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 if a[midIndex] > key { From 510f3da1a0e445c3c1ec4aec69f1731a86acfbc4 Mon Sep 17 00:00:00 2001 From: Mick Bennett Date: Fri, 27 Mar 2020 00:00:03 -0700 Subject: [PATCH 310/327] updated depricated hashable values to hash into methods --- Graph/Graph/Edge.swift | 10 ++++------ Graph/Graph/Vertex.swift | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Graph/Graph/Edge.swift b/Graph/Graph/Edge.swift index ac5ed6a25..b69937895 100644 --- a/Graph/Graph/Edge.swift +++ b/Graph/Graph/Edge.swift @@ -29,12 +29,10 @@ extension Edge: CustomStringConvertible { extension Edge: Hashable { - public var hashValue: Int { - var string = "\(from.description)\(to.description)" - if weight != nil { - string.append("\(weight!)") - } - return string.hashValue + public func hash(into hasher: inout Hasher) { + hasher.combine(from.description) + hasher.combine(to.description) + hasher.combine(weight) } } diff --git a/Graph/Graph/Vertex.swift b/Graph/Graph/Vertex.swift index 758a367bb..47499dcc6 100644 --- a/Graph/Graph/Vertex.swift +++ b/Graph/Graph/Vertex.swift @@ -24,8 +24,9 @@ extension Vertex: CustomStringConvertible { extension Vertex: Hashable { - public var hashValue: Int { - return "\(data)\(index)".hashValue + public func hash(into hasher: inout Hasher) { + hasher.combine(data) + hasher.combine(index) } } From 409ffd6921441afb56a7ea68c73a0f2c9516c809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sarp=20G=C3=BCney=20Ba=C5=9Faraner?= Date: Thu, 7 May 2020 10:35:45 +0300 Subject: [PATCH 311/327] fix typo Dinstance -> Distance --- HaversineDistance/HaversineDistance.playground/Contents.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HaversineDistance/HaversineDistance.playground/Contents.swift b/HaversineDistance/HaversineDistance.playground/Contents.swift index 3d8d60f54..ed89b4462 100644 --- a/HaversineDistance/HaversineDistance.playground/Contents.swift +++ b/HaversineDistance/HaversineDistance.playground/Contents.swift @@ -1,6 +1,6 @@ import UIKit -func haversineDinstance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double { +func haversineDistance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double { let haversin = { (angle: Double) -> Double in return (1 - cos(angle))/2 @@ -27,4 +27,4 @@ let amsterdam = (52.3702, 4.8952) let newYork = (40.7128, -74.0059) // Google says it's 5857 km so our result is only off by 2km which could be due to all kinds of things, not sure how google calculates the distance or which latitude and longitude google uses to calculate the distance. -haversineDinstance(la1: amsterdam.0, lo1: amsterdam.1, la2: newYork.0, lo2: newYork.1) +haversineDistance(la1: amsterdam.0, lo1: amsterdam.1, la2: newYork.0, lo2: newYork.1) From 7a77f3fa8abbdc0ee68b77b84d56b3e1eaf61087 Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 11:57:00 -0500 Subject: [PATCH 312/327] Update Readme for code modification Update to reflect alternative of using .isMultiple(of:) method instead of modulo (%) operator --- Fizz Buzz/README.markdown | 97 ++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 28 deletions(-) diff --git a/Fizz Buzz/README.markdown b/Fizz Buzz/README.markdown index 8c250da27..be516bd46 100644 --- a/Fizz Buzz/README.markdown +++ b/Fizz Buzz/README.markdown @@ -16,46 +16,48 @@ The modulus operator `%` is the key to solving fizz buzz. The modulus operator returns the remainder after an integer division. Here is an example of the modulus operator: -| Division | Division Result | Modulus | Modulus Result | -| ------------- | -------------------------- | --------------- | ---------------:| -| 1 / 3 | 0 with a remainder of 3 | 1 % 3 | 1 | -| 5 / 3 | 1 with a remainder of 2 | 5 % 3 | 2 | -| 16 / 3 | 5 with a remainder of 1 | 16 % 3 | 1 | +| Division | Division Result | Modulus | Modulus Result| +| ----------- | --------------------- | ------------- | :-----------: | +| 1 / 3 | 0 with a remainder of 3 | 1 % 3 | 1 | +| 5 / 3 | 1 with a remainder of 2 | 5 % 3 | 2 | +| 16 / 3 | 5 with a remainder of 1 | 16 % 3 | 1 | A common approach to determine if a number is even or odd is to use the modulus operator: -| Modulus | Result | Swift Code | Swift Code Result | Comment | -| ------------- | ---------------:| ------------------------------- | -----------------:| --------------------------------------------- | -| 6 % 2 | 0 | `let isEven = (number % 2 == 0)` | `true` | If a number is divisible by 2 it is *even* | -| 5 % 2 | 1 | `let isOdd = (number % 2 != 0)` | `true` | If a number is not divisible by 2 it is *odd* | +| Modulus | Result | Swift Code | Swift Code
    Result | Comment | +| -------- | :-----:| -------------------------------- | :----------------:| --------------------------------------------- | +| 6 % 2 | 0 | `let isEven = (number % 2 == 0)` | `true` | If a number is divisible by 2 it is *even* | +| 5 % 2 | 1 | `let isOdd = (number % 2 != 0)` | `true` | If a number is not divisible by 2 it is *odd* | + +Alternatively, Swift's built in function .isMultiple(of:) can be used, i.e. 6.isMultiple(of: 2) will return true, 5.isMultiple(of: 2) will return false ## Solving fizz buzz -Now we can use the modulus operator `%` to solve fizz buzz. +Now we can use the modulus operator `%` or .isMultiple(of:) method to solve fizz buzz. Finding numbers divisible by three: -| Modulus | Modulus Result | Swift Code | Swift Code Result | -| ------- | --------------:| ------------- |------------------:| -| 1 % 3 | 1 | `1 % 3 == 0` | `false` | -| 2 % 3 | 2 | `2 % 3 == 0` | `false` | -| 3 % 3 | 0 | `3 % 3 == 0` | `true` | -| 4 % 3 | 1 | `4 % 3 == 0` | `false` | +| Modulus | Modulus
    Result | Swift Code
    using Modulo | Swift Code
    using .isMultiple(of:) | Swift Code
    Result | +| ------- | :---------------: | -------------------------- | ------------------------------------ | ------------------- | +|1 % 3 | 1 | `1 % 3 == 0` | `1.isMultiple(of: 3)` | `false` | +|2 % 3 | 2 | `2 % 3 == 0` | `2.isMultiple(of: 3)` | `false` | +|3 % 3 | 0 | `3 % 3 == 0` | `3.isMultiple(of: 3)` | `true` | +|4 % 3 | 1 | `4 % 3 == 0` | `4.isMultiple(of: 3)` | `false` | Finding numbers divisible by five: -| Modulus | Modulus Result | Swift Code | Swift Code Result | -| ------- | --------------:| ------------- |------------------:| -| 1 % 5 | 1 | `1 % 5 == 0` | `false` | -| 2 % 5 | 2 | `2 % 5 == 0` | `false` | -| 3 % 5 | 3 | `3 % 5 == 0` | `false` | -| 4 % 5 | 4 | `4 % 5 == 0` | `false` | -| 5 % 5 | 0 | `5 % 5 == 0` | `true` | -| 6 % 5 | 1 | `6 % 5 == 0` | `false` | +| Modulus | Modulus
    Result | Swift Code
    using Modulo | Swift Code
    using .isMultiple(of:) | Swift Code
    Result | +| ------- | :---------------: | -------------------------- | ------------------------------------ | -------------------- | +| 1 % 5 | 1 | `1 % 5 == 0` | `1.isMultiple(of: 5)` | `false` | +| 2 % 5 | 2 | `2 % 5 == 0` | `2.isMultiple(of: 5)` | `false` | +| 3 % 5 | 3 | `3 % 5 == 0` | `3.isMultiple(of: 5)` | `false` | +| 4 % 5 | 4 | `4 % 5 == 0` | `4.isMultiple(of: 5)` | `false` | +| 5 % 5 | 0 | `5 % 5 == 0` | `5.isMultiple(of: 5)` | `true` | +| 6 % 5 | 1 | `6 % 5 == 0` | `6.isMultiple(of: 5)` | `false` | ## The code -Here is a simple implementation in Swift: +Here is a simple implementation in Swift using Modulus approach ```swift func fizzBuzz(_ numberOfTurns: Int) { @@ -79,7 +81,31 @@ func fizzBuzz(_ numberOfTurns: Int) { } ``` -Put this code in a playground and test it like so: +Here is simple implementation in Swift using .isMultiple(of:) and switch statement + +```swift +func fizzBuzz(_ numberOfTurns: Int) { + guard numberOfTurns >= 1 else { + print("Number of turns must be >= 1") + return + } + + for i in 1...numberOfTurns { + switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) { + case (false, false): + print("\(i)") + case (true, false): + print("Fizz") + case (false, true): + print("Buzz") + case (true, true): + print("Fizz Buzz") + } + } +} +``` + +Put either code in a playground and test it like so: ```swift fizzBuzz(15) @@ -87,10 +113,25 @@ fizzBuzz(15) This will output: - 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, Fizz Buzz +1 +2 +Fizz +4 +Buzz +Fizz +7 +8 +Fizz +Buzz +11 +Fizz +13 +14 +Fizz Buzz ## See also [Fizz buzz on Wikipedia](https://en.wikipedia.org/wiki/Fizz_buzz) -*Written by [Chris Pilcher](https://github.com/chris-pilcher)* +*Originally written by [Chris Pilcher](https://github.com/chris-pilcher)*
    +*Updated by [Lance Rettberg](https://github.com/l-rettberg)* From 99d769d03c0cfee1b92b63aeeb1b203811eaddc8 Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 12:02:06 -0500 Subject: [PATCH 313/327] Update FizzBuzz Update to 1) add guard, 2) use .isMultiple(of:), 3) use switch statement --- Fizz Buzz/FizzBuzz.swift | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Fizz Buzz/FizzBuzz.swift b/Fizz Buzz/FizzBuzz.swift index b6bb410e7..704ea7c6b 100644 --- a/Fizz Buzz/FizzBuzz.swift +++ b/Fizz Buzz/FizzBuzz.swift @@ -1,19 +1,21 @@ -func fizzBuzz(_ numberOfTurns: Int) { - for i in 1...numberOfTurns { - var result = "" +// Updated for Xcode Version 11.4.1 (11E503a) - if i % 3 == 0 { - result += "Fizz" +func fizzBuzz2(_ numberOfTurns: Int) { + guard numberOfTurns >= 1 else { + print("Number of turns must be >= 1") + return } - - if i % 5 == 0 { - result += (result.isEmpty ? "" : " ") + "Buzz" - } - - if result.isEmpty { - result += "\(i)" + + for i in 1...numberOfTurns { + switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) { + case (false, false): + print("\(i)") + case (true, false): + print("Fizz") + case (false, true): + print("Buzz") + case (true, true): + print("Fizz Buzz") + } } - - print(result) - } } From 71431b12042a2dc17eb9c170a9fa5c731942462d Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 12:09:54 -0500 Subject: [PATCH 314/327] Update --- Fizz Buzz/FizzBuzz.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fizz Buzz/FizzBuzz.swift b/Fizz Buzz/FizzBuzz.swift index 704ea7c6b..2e66b26f4 100644 --- a/Fizz Buzz/FizzBuzz.swift +++ b/Fizz Buzz/FizzBuzz.swift @@ -1,6 +1,6 @@ // Updated for Xcode Version 11.4.1 (11E503a) -func fizzBuzz2(_ numberOfTurns: Int) { +func fizzBuzz(_ numberOfTurns: Int) { guard numberOfTurns >= 1 else { print("Number of turns must be >= 1") return From f94bccc68d017bbc61cb774f7642dd25b25f1d4a Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 14:41:39 -0500 Subject: [PATCH 315/327] Updates to 1) add guard, 2) use .isMultiple(of:) and 3) use switch statement --- Fizz Buzz/FizzBuzz.playground/Contents.swift | 34 ++++++++++---------- Fizz Buzz/FizzBuzz.swift | 4 +-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Fizz Buzz/FizzBuzz.playground/Contents.swift b/Fizz Buzz/FizzBuzz.playground/Contents.swift index ae966bbcc..2ab13b362 100644 --- a/Fizz Buzz/FizzBuzz.playground/Contents.swift +++ b/Fizz Buzz/FizzBuzz.playground/Contents.swift @@ -1,23 +1,23 @@ -// last checked with Xcode 10.0 (10A255) +// Last checked with Xcode Version 11.4.1 (11E503a) func fizzBuzz(_ numberOfTurns: Int) { - for i in 1...numberOfTurns { - var result = "" - - if i % 3 == 0 { - result += "Fizz" + guard numberOfTurns >= 1 else { + print("Number of turns must be >= 1") + return } - - if i % 5 == 0 { - result += (result.isEmpty ? "" : " ") + "Buzz" + + for i in 1...numberOfTurns { + switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) { + case (false, false): + print("\(i)") + case (true, false): + print("Fizz") + case (false, true): + print("Buzz") + case (true, true): + print("Fizz Buzz") + } } - - if result.isEmpty { - result += "\(i)" - } - - print(result) - } } -fizzBuzz(100) +fizzBuzz(15) diff --git a/Fizz Buzz/FizzBuzz.swift b/Fizz Buzz/FizzBuzz.swift index 2e66b26f4..bf753e648 100644 --- a/Fizz Buzz/FizzBuzz.swift +++ b/Fizz Buzz/FizzBuzz.swift @@ -1,4 +1,4 @@ -// Updated for Xcode Version 11.4.1 (11E503a) +// Last checked with Xcode Version 11.4.1 (11E503a) func fizzBuzz(_ numberOfTurns: Int) { guard numberOfTurns >= 1 else { @@ -18,4 +18,4 @@ func fizzBuzz(_ numberOfTurns: Int) { print("Fizz Buzz") } } -} +} \ No newline at end of file From 6a9ec9628099601714655ad42237d8948b2cfc05 Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 16:45:31 -0500 Subject: [PATCH 316/327] Remove file --- Fizz Buzz/FizzBuzz.playground/contents.xcplayground | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 Fizz Buzz/FizzBuzz.playground/contents.xcplayground diff --git a/Fizz Buzz/FizzBuzz.playground/contents.xcplayground b/Fizz Buzz/FizzBuzz.playground/contents.xcplayground deleted file mode 100644 index 5da2641c9..000000000 --- a/Fizz Buzz/FizzBuzz.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From e3b3126f819ec57b9759cd4b80f639b1d39b440a Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 16:47:18 -0500 Subject: [PATCH 317/327] Delete IDEWorkspaceChecks.plist --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - From 51b0c2b5a2abed1a90241e64869ccd173b54a1e7 Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 16:47:30 -0500 Subject: [PATCH 318/327] Delete contents.xcworkspacedata --- .../playground.xcworkspace/contents.xcworkspacedata | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata b/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - From 4617d9401be60101c12e100f428c0b460de0a210 Mon Sep 17 00:00:00 2001 From: jinthislife <8064873+jinthislife@users.noreply.github.com> Date: Mon, 11 May 2020 15:30:38 +1000 Subject: [PATCH 319/327] Update README.markdown remove duplicate parameter --- Binary Search Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index 0b382f204..57d1f4bff 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -557,7 +557,7 @@ As a result, doing `tree.search(100)` gives nil. You can check whether a tree is a valid binary search tree with the following method: ```swift - public func isBST(minValue minValue: T, maxValue: T) -> Bool { + public func isBST(minValue: T, maxValue: T) -> Bool { if value < minValue || value > maxValue { return false } let leftBST = left?.isBST(minValue: minValue, maxValue: value) ?? true let rightBST = right?.isBST(minValue: value, maxValue: maxValue) ?? true From d8d165208465c8c725eda950e8cb2ddb3d7cfdca Mon Sep 17 00:00:00 2001 From: Yossa Bourne Date: Thu, 11 Jun 2020 09:56:40 +0700 Subject: [PATCH 320/327] Fix Swift (language) typos --- Introsort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Introsort/README.markdown b/Introsort/README.markdown index 376703cf7..3e596ee89 100644 --- a/Introsort/README.markdown +++ b/Introsort/README.markdown @@ -2,7 +2,7 @@ Goal: Sort an array from low to high (or high to low). -IntroSort is the algorithm used by swift to sort a collection. Introsort is an hybrid algorithm invented by David Musser in 1993 with the purpose of giving a generic sorting algorithm for the C++ standard library. The classic implementation of introsort expect a recursive Quicksort with fallback to Heapsort in case the recursion depth level reached a certain max. The maximum depends on the number of elements in the collection and it is usually 2 * log(n). The reason behind this “fallback” is that if Quicksort was not able to get the solution after 2 * log(n) recursions for a branch, probably it hit its worst case and it is degrading to complexity O( n^2 ). To optimise even further this algorithm, the swift implementation introduce an extra step in each recursion where the partition is sorted using InsertionSort if the count of the partition is less than 20. +IntroSort is the algorithm used by Swift to sort a collection. Introsort is an hybrid algorithm invented by David Musser in 1993 with the purpose of giving a generic sorting algorithm for the C++ standard library. The classic implementation of introsort expect a recursive Quicksort with fallback to Heapsort in case the recursion depth level reached a certain max. The maximum depends on the number of elements in the collection and it is usually 2 * log(n). The reason behind this “fallback” is that if Quicksort was not able to get the solution after 2 * log(n) recursions for a branch, probably it hit its worst case and it is degrading to complexity O( n^2 ). To optimise even further this algorithm, the Swift implementation introduce an extra step in each recursion where the partition is sorted using InsertionSort if the count of the partition is less than 20. The number 20 is an empiric number obtained observing the behaviour of InsertionSort with lists of this size. From 9bc6aad9aaa56ce53ea7319f52c25585651e737a Mon Sep 17 00:00:00 2001 From: Roberto Efrain Hernandez Date: Wed, 10 Jun 2020 23:44:40 -0700 Subject: [PATCH 321/327] Updating how String can be casted into an Array. Just wanted to update the syntax from Array(self.characters) to Array(self). Similarly for casting of the ptnr String. --- Knuth-Morris-Pratt/KnuthMorrisPratt.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift index 81bc65278..be0cd961d 100644 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift @@ -12,8 +12,8 @@ extension String { func indexesOf(ptnr: String) -> [Int]? { - let text = Array(self.characters) - let pattern = Array(ptnr.characters) + let text = Array(self) + let pattern = Array(ptnr) let textLength: Int = text.count let patternLength: Int = pattern.count From abfa66b02d35b6320a5e404241db94d4317386d6 Mon Sep 17 00:00:00 2001 From: msalvacion Date: Thu, 11 Jun 2020 15:32:05 -0700 Subject: [PATCH 322/327] Fix: Typos in Heap README.markdown Added missing word and fixed a typo --- Heap/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Heap/README.markdown b/Heap/README.markdown index 6c65fe9c8..fee881129 100755 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -82,7 +82,7 @@ array[parent(i)] >= array[i] Verify that this heap property holds for the array from the example heap. -As you can see, these equations allow us to find the parent or child index for any node without the need for pointers. It is complicated than just dereferencing a pointer, but that is the tradeoff: we save memory space but pay with extra computations. Fortunately, the computations are fast and only take **O(1)** time. +As you can see, these equations allow us to find the parent or child index for any node without the need for pointers. It is more complicated than just dereferencing a pointer, but that is the tradeoff: we save memory space but pay with extra computations. Fortunately, the computations are fast and only take **O(1)** time. It is important to understand this relationship between array index and position in the tree. Here is a larger heap which has 15 nodes divided over four levels: @@ -164,7 +164,7 @@ All of the above take time **O(log n)** because shifting up or down is expensive - `buildHeap(array)`: Converts an (unsorted) array into a heap by repeatedly calling `insert()`. If you are smart about this, it can be done in **O(n)** time. -- [Heap sort](../Heap%20Sort/). Since the heap is an array, we can use its unique properties to sort the array from low to high. Time: **O(n lg n).** +- [Heap sort](../Heap%20Sort/). Since the heap is an array, we can use its unique properties to sort the array from low to high. Time: **O(n log n).** The heap also has a `peek()` function that returns the maximum (max-heap) or minimum (min-heap) element, without removing it from the heap. Time: **O(1)**. From f30e53c3cb45af31f8b80c35a8c4ee781d1ee311 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 15 Jun 2020 18:23:10 -0400 Subject: [PATCH 323/327] Fixes a few typos --- Introsort/README.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Introsort/README.markdown b/Introsort/README.markdown index 3e596ee89..280950928 100644 --- a/Introsort/README.markdown +++ b/Introsort/README.markdown @@ -2,7 +2,9 @@ Goal: Sort an array from low to high (or high to low). -IntroSort is the algorithm used by Swift to sort a collection. Introsort is an hybrid algorithm invented by David Musser in 1993 with the purpose of giving a generic sorting algorithm for the C++ standard library. The classic implementation of introsort expect a recursive Quicksort with fallback to Heapsort in case the recursion depth level reached a certain max. The maximum depends on the number of elements in the collection and it is usually 2 * log(n). The reason behind this “fallback” is that if Quicksort was not able to get the solution after 2 * log(n) recursions for a branch, probably it hit its worst case and it is degrading to complexity O( n^2 ). To optimise even further this algorithm, the Swift implementation introduce an extra step in each recursion where the partition is sorted using InsertionSort if the count of the partition is less than 20. +IntroSort is the algorithm used by Swift to sort a collection. Introsort is an hybrid algorithm invented by David Musser in 1993 with the purpose of giving a generic sorting algorithm for the C++ standard library. + +The classic implementation of introsort uses a recursive Quicksort with a fallback to Heapsort in the case where the recursion depth level reached a certain maximum value. The maximum depends on the number of elements in the collection and it is usually 2 * log(n). The reason behind this “fallback” is that if Quicksort was not able to get the solution after 2 * log(n) recursions for a branch, probably it hit its worst case and it is degrading to complexity O( n^2 ). To optimise even further this algorithm, the Swift implementation introduce an extra step in each recursion where the partition is sorted using InsertionSort if the count of the partition is less than 20. The number 20 is an empiric number obtained observing the behaviour of InsertionSort with lists of this size. From 73f009209e99eaed53a6c81bf72dae83a5397cb4 Mon Sep 17 00:00:00 2001 From: Ahmed Abdulkareem Rezik Date: Thu, 9 Jul 2020 14:33:03 +0200 Subject: [PATCH 324/327] Fixed Hashable Conformance to hash(into:) --- Graph/Graph/Edge.swift | 14 +++++++------- Graph/Graph/Vertex.swift | 6 ++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Graph/Graph/Edge.swift b/Graph/Graph/Edge.swift index ac5ed6a25..61cb576d1 100644 --- a/Graph/Graph/Edge.swift +++ b/Graph/Graph/Edge.swift @@ -29,13 +29,13 @@ extension Edge: CustomStringConvertible { extension Edge: Hashable { - public var hashValue: Int { - var string = "\(from.description)\(to.description)" - if weight != nil { - string.append("\(weight!)") - } - return string.hashValue - } + public func hash(into hasher: inout Hasher) { + hasher.combine(from) + hasher.combine(to) + if weight != nil { + hasher.combine(weight) + } + } } public func == (lhs: Edge, rhs: Edge) -> Bool { diff --git a/Graph/Graph/Vertex.swift b/Graph/Graph/Vertex.swift index 758a367bb..cdf39ba62 100644 --- a/Graph/Graph/Vertex.swift +++ b/Graph/Graph/Vertex.swift @@ -24,8 +24,10 @@ extension Vertex: CustomStringConvertible { extension Vertex: Hashable { - public var hashValue: Int { - return "\(data)\(index)".hashValue + public func hasher(into hasher: inout Hasher){ + + hasher.combine(data) + hasher.combine(index) } } From 0513f7d1d0432d844357f5b931bfc5e0d1940870 Mon Sep 17 00:00:00 2001 From: Ahmed Abdulkareem Rezik Date: Thu, 9 Jul 2020 14:37:37 +0200 Subject: [PATCH 325/327] Fixed Conformance to Hashable Protocol in Vertex and Edge structs --- Graph/Graph/Edge.swift | 14 ++++++++------ Graph/Graph/Vertex.swift | 12 +++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Graph/Graph/Edge.swift b/Graph/Graph/Edge.swift index 61cb576d1..1f29e07dd 100644 --- a/Graph/Graph/Edge.swift +++ b/Graph/Graph/Edge.swift @@ -29,13 +29,15 @@ extension Edge: CustomStringConvertible { extension Edge: Hashable { + public func hash(into hasher: inout Hasher) { - hasher.combine(from) - hasher.combine(to) - if weight != nil { - hasher.combine(weight) - } - } + hasher.combine(from) + hasher.combine(to) + if weight != nil { + hasher.combine(weight) + } + } + } public func == (lhs: Edge, rhs: Edge) -> Bool { diff --git a/Graph/Graph/Vertex.swift b/Graph/Graph/Vertex.swift index cdf39ba62..45b2c3088 100644 --- a/Graph/Graph/Vertex.swift +++ b/Graph/Graph/Vertex.swift @@ -24,11 +24,13 @@ extension Vertex: CustomStringConvertible { extension Vertex: Hashable { - public func hasher(into hasher: inout Hasher){ - - hasher.combine(data) - hasher.combine(index) - } + + + public func hasher(into hasher: inout Hasher){ + + hasher.combine(data) + hasher.combine(index) + } } From 4311cad2e332b9454c1189bddcbbca5f156a3d4c Mon Sep 17 00:00:00 2001 From: Samuel Huang Date: Wed, 22 Jul 2020 13:26:35 -0700 Subject: [PATCH 326/327] Update BTree.swift Fix spelling of swift markers - rename `Travelsals` to `Traversals` --- B-Tree/BTree.playground/Sources/BTree.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/B-Tree/BTree.playground/Sources/BTree.swift b/B-Tree/BTree.playground/Sources/BTree.swift index 2693eb308..2ed0b2593 100644 --- a/B-Tree/BTree.playground/Sources/BTree.swift +++ b/B-Tree/BTree.playground/Sources/BTree.swift @@ -86,7 +86,7 @@ extension BTreeNode { } } -// MARK: BTreeNode extension: Travelsals +// MARK: BTreeNode extension: Traversals extension BTreeNode { @@ -443,7 +443,7 @@ public class BTree { } } -// MARK: BTree extension: Travelsals +// MARK: BTree extension: Traversals extension BTree { /** From 617187bf4c36ab57948592d403e295cf8127d664 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Sat, 29 Aug 2020 13:37:23 -0700 Subject: [PATCH 327/327] Update style of Graph --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Graph/Graph/Edge.swift | 15 +++++++-------- 3 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Graph/Graph/Edge.swift b/Graph/Graph/Edge.swift index 3c95f9666..9ddd4e23d 100644 --- a/Graph/Graph/Edge.swift +++ b/Graph/Graph/Edge.swift @@ -29,14 +29,13 @@ extension Edge: CustomStringConvertible { extension Edge: Hashable { - public func hash(into hasher: inout Hasher) { - hasher.combine(from) - hasher.combine(to) - if weight != nil { - hasher.combine(weight) - } - } - + public func hash(into hasher: inout Hasher) { + hasher.combine(from) + hasher.combine(to) + if weight != nil { + hasher.combine(weight) + } + } }

    EwNTrCh(m?6Wp<&*1KTEj~B(pwGn5`$#QIN$rR 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 literal 0 HcmV?d00001 diff --git a/Sparse Table/Images/structure.png b/Sparse Table/Images/structure.png new file mode 100644 index 0000000000000000000000000000000000000000..88902df0c199e6509f54080b9268d1f7c6b5c345 GIT binary patch literal 100125 zcmeFZ2T+vD);5X)0-}N<0umJvl_W`WPy|$>fgB}=0VIbZ2q-8>5EPWGD4=A?3{eRJ z5|o^kC|N*;40pY_-3K`PoLhD4R{ei{^_?oVb7uPOUcGw7XRUr8DJjStK6vsV4i3)Y zYgez_#KFPO!@iGy?KxS6D+(ltp*1|?f-V>6Ty4$jp_&r}K2Zq=TM z)x1e~?W`B!RiYB2uPMKD@Lu}_hTsu0OI%jUijczZ;CQ9>g`BiU14o_pm6{sf)S}nJ zy1F8@a__pR-sKkn_riDIl2lZq&I1;ZI6h{071WD-$ za5}yX6A|MuFidvZqE55{qt znTypQMB7vPaeOyr{5FqIYVFe*7FIEOd7X5SNKmkll=aD}i?SOW3abP9i9uC{*)27h zY!q)pHdbC0qp;Cic7mJv!-fGeV;AlPMxHtp6h3^YBTa~vU(Wk2Y22~b(pN609-K20 zQ#I$TSmLRyu(4h92>L{lPNlbhxv&tmb>U&|DP#ZaLAT+~Aoi!Lm(jf5x}?WgYu+J}PM-|6R-eOw6_&DP6FAKrQMvL=9ApUhC?%jjhfH@r&whdom2 zTz6~-YNV(yxT)nBWq2bgj2rIAj(O+abD=P-JW%hJbtU#J zm)ld^h%tJGp?fwi-U5RBhg2f0b9(ayIEAlU1y6r7B9N+YrxHGW{xQ|!G}}G=Gnxcb z*Ukv@UKi_7(z$dy^)Ypj_uX#<>-&fw-jT&GWFY(5vpTu%vO4}`;2>$uF`I7VH z0;wOTdvWK!z2)`qH9zC|=qJG_+XX873RAE7shed@NBF%`X>D|Sap(PdZO)|Qr`{!a z{)l7--_GuS_biovO@X^+J^ff%=B5~ZVXW09r>EIhY1g`ygjk!LC&exSbGv{Jut#Ivq!g88L=qpKm@*MvyY%(wzSGj9 zr(~bpG!%VL-WAx&Ph6Od(ZTY z)R-L!E$$Dj9B6;AXh3gsy0KinfIPK9Pvpqhx0U7nZseup8P$_Njn@zK2am@kv{R(swd0Cwy>tp!494|G}!KgO?t?F}!)=R^2(jvlQn@ z&RLU_lOH~=O`ddio}A)bI4j+a;?&NxKC=Nc{Tr(5QrC^H*E~&UU1ViF z8+CT=T=p}Hv#Mv~ZkHyAB!5uKQhs#1_J;bK_qrqgb;Qb{?;e@oJFn{SVuG%X_?_sX z$9F#cG`LGCONFMQpeixH!gni|G*>S7X0DI9r8(}zyNM$ca}(KZtgVVEPF!4xL_GIj zG-!PksVi<+=T$I?ZW8D(cs6t-aFS+8$Dr6Z|A1n`m7&aP_CUo*wg#LAwg!jD#mL~C zyX?ei=QOf&98I-bC+IUS_PdLixYaHv49!|3bf4({(ruT!WSVbIGVx;qZ+v(h^`$Vr zC8NG|vAv}^d)PqLHBEJ?Ufz2CEj^Co=R2Y%%)`YcwhVitRT`5l%! zJa{OalIEhb;Z-hsE;*iF(@sMHz1JqZU8b=&(!RJG;2Tg39U5w=X0M)=my@jRB;XUla zXGqT!D3Hn}N8hdSHy<%jHdVH0vuwyYlCPt$ZM|Xs>PzMDqscRQa_ib53%HgT<{XAq zn3%ipQx83b{V{LolIT1$KQ;e#Ngu83Dmr)Z*Qo34g2#-(OxUMal`?F|q z{<0O1v30I3hOJ{;c{pwN3ht%t3&uUXzXjIUKUw|rxM#$yku;0<@quvi!uaZ(7D?BxS#4|20vltS!Gc8RH_K*od~>s8>tyXL_RI=$ z(Q(e~*H|CLwT8%D4^r%p5E0D>`X@2Qa`1>OMNnRf9j*)aP-sYu>H!H!s7*1`JEiCWMYkUY;;sh zH8&I2_uYAZH;(YAJO$tJI{hhOSl_R8|jMjbnAS@>Pq^ziPd;myQBj;7Ah zDiL+UdgeR{r*)@(j?r{@lO|7I|GS@Q0>$#^o;u6fe7k(7nV>UthmRk=Q7Hk2OILE#<8b&dWB4rMbUZE4@whuIODtN|Z&kg*nz@R`*swyT8TS z5jo*zkLE4CkEc>3F(f=B5p?@xDrGj8`9?Z=WIhI6q_q=t{82DBXURgza(yDCNYDXy zk!n%<@U_FVERu>B`HJ{smm5~|-`!eGIy$V$GQ18<+2nSZW@g`*aEi+|DI=Is@m!8x^_h>9TT0dgHAOAiaCP0 zZQ4$y{mnDo{heHIhvbq}$5yB}`8oOy6}n8TRHg;>*yPXlzi>>NzgnR|rk$gk29rF1UY6KSJ8@0^az zMjl8wKuQ9a3n=D z@q>=-ub{;P$t4?VVF70w`V~$D9JIc0pM;Uo+5v}wZ~spz0dDSMcf;X&ovTAtqCWWpr9b<1#V7mZgv>KZs%fUf5(~K%8v2(B!A|)Vq|AvYj)S(%-V_pnfH#q zwS&Fr>C?zUfB)|{okq@P|60k)?yqgZ204*mIJr13aQ;0vJSu{GE2L!RY=ly~VrFS% zWe01Baq(W{7TJE_-+ubnk~lm3k(xGD8l(S z^TiH2%Ls13dC-_$QM?WR?ne#>{=tX;oc;YT@;P-=-9Kp>2S)%e ztEGQ*ZA7K{9d+6j9+TFmAuq0kEpwZ{ikHwA_U7_;K8~BrkaKW3DcOh36wGj{Vcj_wMQS@chGy2n~hDNKs?&v<}GrJ3+`d-j+@O zM(FR6!`CG;V^VCX*!J$@_s@iRqPV;F_h*3+)_oO@>2*e#|NJv-^3eZo@_$eAkGSlX z+yCL>dX~uE-u?<2jV|6?og~ds}Y4y2|SstM-Yx~4-yFBVOKsN12edwS@H#NV)c zRH(d}c&fLMMBp(?@NnC5QJcZa&OA#^R9_Kazxz_3z|dnJ{jaaD zNs5~?g2|8|BPPs?Dp*cb*u(ZK#j6u3bC`h*4(Y&?s-+zAZv9YR#akTs# z#XpPF61Vv)$$7q(WoUUQIQRvRN%b8+TE}nE6bN-8G57R@g)N*;?>6o*t&O)RkrL zRJR$r#MdIq){O*PV}%?hP9;pScPenWEi~{C<(F+(M%#bA#${CZRI*!W`^iOeQdCEW z>g*ooN%$NrUToK#`^?i+`D?s|HN9wtwNoK6$EZGhzO*MP+V;9nV{;~KNl6O~n2m*n z@tz6F8Sqw#^9a7=CL%vvxVoS+zWr5Xq$rAvMB^)ahO|n+5Zo);U`*o`_IpnY zRZN8MvE`rg;cx~Pd0hA7`LhFAj_wUXdxl&EautY@s6gzvNl8&A_ohzl*|x+c_@0%N z7e~n$nnhrp(YLuT_PQZu*l9|+?KxzY6EMr68OOb|h#|8ihut{F&>W4-l8R9$+ryX* zm}PCBZ6uH=d6uD*?y_6{nZ2^0Dv{Y&kjupl0`pHU$m<}?eemp&qrj9)u;SsHgdg{; zf_G9D=1^O_a1!RQ2U&4y`-v>Mi{MOMiOlI6h~^9(B+R4EzbGxehy90Mf{qf-^&yY$ zAbjU6rV4PlcI|zsM5Lem;3ViBxUcVCMuNcrhE#vElDUWDbsp$d)+>CvhZa*h7_!jX zEeEs2!7QG9Jo>L?NcI9%Jn*n+&m?&MEFeWX@(mAhyao~Bz9q|ZYWF&L=5TW9rxMc<;YKzW zc*y}aw~M{UB|&l@3q|6Ca32SKgW40G zdF=xUARrt;MD7sq1x?u87rJ{xq^550>`=!iLYPJeJ}$KPf8IL{q5$sS1YoCLr{FM1 zZ1(lW?wv*so;7H%N(SbIAo5MHQ=E{)_#Y_WltNzl{jRKe)&n}53p1G6>K|Vc3_d^S z;xcbd7MRNXXfAf4!m;6+101ebB%Gp!^jpR~rx;JSpZX%|VN$H?`F?Nrs$Oa}E$!!M8{Do|XpTRDX%^ zwx_*l=^v&jCa54XS2=$kqI{1cH`GjT;asEe?3H6~;%igcBg#E->%%NVKN5n|tEMG0 zwaKJo5VOny!c~+xu~(xhAD1`A2oHG?(4EaFSNJeth?+%swjO%O7K4qCA2+WhN&qbzEfvM8+F?;RK1|dW| zmFU@$j!A+`SPIlqM`>ISy#RZsn8bI`f4q|lV2tlFb202aQckZ;@9ENR6+4AY?Z9vg zIG>O-uzs4>PK?bWHK1K*d=|g)lf$y!g9kYnFq9Fn*U;2!1R6Jq&ptkg%77 zK8T&qx!{ZF=OM6=RQee5T~-TRzB9P|Z-*BVJuHTUSkSpNw8#C+pJC{@0gs*s z4Q7oO*z31>(}4gR3j;%hYeWk=t5TXl*QqjA2BoUtnk9NCG1OkmN z;9kbE%&X;g6C9}qLRVSE?*NZZf$u;c2ZOtlU@tA$sGTy04>Lpn+Q2%8J8ejCvvZgd zC$O%>a1kxtb%qy&R1a6{`^y&mvdi2^9rR&%(%n@GY|2#B;f)i+>b25}g^ z-dcBc_tD^Zg#yN4u)Vu~fDCq~{K)}8F-NM#8*URJn*Y)mqz=)%Oq5T?h(X;A%}YychTLx{A%j;MBt z795Z*u%c19@DLKNJ0P0=KsjkID@x$77em`PVfZ{F3|CBhyvL33=9H&vV_qdBFluOO zP6{c&(YiQ5e&?kH!e)2lj1SXpVGLx+1b5h(V|J@}zK(T7{90y=8?DRm6Pu~5nrfRG zS_=C0Zv=?@NFM)&-@`Z3isS^gp!|(SU5EAr$cNI(eGgOXFHW>^p*k~{%L&AkHnSm- z>clu%3pRU9=XMOXspL%>t)>W!zYa6Ms0UvBtOHm>uU^n|J53?nJ%*->m`O7* zRU`Mjj`Q~i0vo?th7#yEet2DCs&Sg_r-j@U>t!(6krB*i(Oy~kh-?TFxyK)m2v3z4 z=5XTmn2qFsW00@`zE!<_^J0%a7ZInbWu4xfk0`5L8H=MIst%lVEW2LeXj_4u?iqUN zN9UhqP*W{97EQ*^&feFpye6Hgo%VbZQ5q2t);V)?>D?y;3d>o#tdID}xfe}tXM)65 ze@M=J(F7;i+22oBw$fm&-<@OT(;t2%)19yc!OBd9V5XL5z4vzul!TBMf4?(hzsp$6 z^9y$_R~=bBm=|`SwzQ|#e0pxEMinLA?BhM{b-fTt-Krp8p~%lO-jj`RlmFoCOmEY} z>&XpmB|&6{70%6i`f>Cwb41Ad6qNI2-JJ_S&eH4MEutQ&?tT-u0s!YZ)jK@6mV>UN*LKQqE@OUkN0H3ys5CyJF*6P z$eyF&^Ic}XQ@b~GffuaaOB*Lu_?kBXhESzgHSQ)h{s;^ail5ky{LjOlS>FrnO*d`> z)6-QxFK%xMiHB4agm*6_5g!G!Q~U8FL;gcz6A4zZPp<7ELd+oudC;aCeKEUteH`L8 z?dLZm31QbKbzt~UW^ReyD}|828Hr68K1Fuz4T};g^AhYH(u@OJI&jwe6dYUpHP9RR zo2D&$jK(5lDjk|?TL`_)U<+oR{@gL2^P0fLiw;~3H_bBZ& z@GCdFl?X?6zedZs{(l4viR=erel_{O*C{DB~HR+Y-phNz+Bgdl$aZ!7yt&_j@q1_uQN*?uaq8*6;d zYj*Q;EAz~IA3`CFOVJlAOv?nxkFna928J?G(a)OqBY>R?t49c#uXh0Bv)5@aI$ zHa{^2S0>*`82r_u$XVuz_~J(_u@Cz&PBn#NvDD!DQfiNbgTK?doeUg;5JeP+DPj*_ zq$$+OJlq9SH!E4hj?!-}*I*9kn`FjByUms?A%1`E12N~eD|fn3ScZ<=j+uQ}qK19ZE)-ped2) z2}n@MqqZGx$Yn62`{l{@h{x6aP2yW_2%O91FwyG&aRQLslOn4>61ZIEhc9JxpFpV& zJB1);Fu?#e8TTE>9`$7;`bB~2Fi-WK*0?r-SOUCNFbhj8!y>!Rp7c{8Y({%un0tLk zx;FK~XoGBrm&&&I^MjoCnL6yrEKUNn6_b9%d)nSg0}hUX7)G6_n*m^M=e)j<3&kAK z&5UW3XN8>^o&v{pxl441+5_jxNkKJQz7yxQ6q+GPDH~!R&SD65PDDsbc^Os^a)Uqq zGP>P9eGlea9pb-OtPamj1}mk{>_l{35^pYoPH8SL;SupNHqsTh&dzYSUL zUs&P}(UkDsm?4$NCz`1`OI$@&$`dD zmMILRgiDb+FZDSkl$4aLn{;O0A&3oxf@zVQ;@|keww?7O9Z1{ZBF-k3hqG%ALaG=X zq2qck6lVc}RTb@*X8O3?mVYjPk`X%=#-bPm`56USd8#XUXMv5uN*Cgd>pGa4q~~!% zMA6vFCo*(YHT0ft+Z9UJUq5u#uG(GBjFFb#E<>0a!gd%{YdUw>{ZG%zAt*2a2b%?` z_3}3YampH6C#{tx`putywx%w1=aQ}*L!I%wXx&f466aE==tl5Onn9RF%{1d8uVhD>JWq< z0qyPW0$b|~B&ic(cfBYc9PKQ1N3V2U&3h?0nVMbK^Tl3arlV}rL9lbPvqr4l<*bg! z%82v&T+PsPgP?P|x&icVgn1-C9noJ(Ej6du(!v!z!d^MFc2aVs_KfQcOj!<`(Cl7% zy0v0S+ooa8U+!Ci{eibFH9Jx+5XNoVf1C4P!M@t{mgsXa014Vh%M{6U?LSg=EHp2 zp-RZ&Huog1YHJ}__i+#1l!x2*#r(=aR*LGU2Cl^K@+-BsetFg~Z#iq``(|gT9UCaS zVGc&kjJSu1uXQ!i9W!S+UV@aznR-jdV$pS) zicD)(Yv;quk%B<2|MV~c#j`x}aVUKs4|S|vQFNcUHPY7O^W-SXX<|B1rqs?RdMS4# zhTyzg+)1bOHEk`oy5yNLY$@fy%H+_Hh3JQ$J`@eXe*6REW7w1a^u=G1(1Vn+7_zsY zzOFlTF1{8&RJpKL^?lmaHyNeg)5ELz10I;-Cdc{jUZwubA*sc5P++N|cV^<5hPbP7 z7W7U!h=%Ipfx@;2dct4W((Zdsv{Q;M&bwPD>Kt|2{5d=HxR!CqQ+&04c}=$Tq~%)U z)6FG+(;k~!a)Ke2v;LS9xz)`4vt@eUL)GRQ9@t!-3@VuQ(+%eIKzk~QEv|Mh4?A$p zNr>wpQHI10XzXvz!4g9}=VPve6b&?L3G>KmvCCa=5{3e5IZkIsR8|w5a3YD%PkSUa zWPHWMQPk5+lTDNNjh44|(-xbC;;R0N!)M)-ni1^&>6oBi^mO!cl=ZA;o%_besG%ae z;4Y`MEdLh$cN=@f$jmGxhil)c%kM zVpZt0ztRyTZG(>Dp@9TV_mzW@>)c1fwjaf5KI<| zn#y7AwhC;kTIn4lE#BJDY5TS|Bxc41i6Z%2tGv_qUIinqAg{XY3v@E4J7jJQ;to6- z8uPFm&`b1S?Dkk{veBz>h|m)j%4d0dVJe+9udK{fMvJe{fBK-@c2k5gP#Ae*;^9sT zpF!OJOq(VULU!~)b1Ia$T}Q6X1oJ>Ye@K_?V4*I1P^~tFrqkg(^v2Im4}B`IQw1hN z)`Q-UK7N%~_-#c1nLta(aqR2@l5hoqbj7^NKaNUDxtr!a&6m&NPZcrSa~qB2pLra& zwNS;CHx|+@OHU{0I^ZW$z5eD6$y2T4e(6>H)FfJK9b8L2B;guO!EM6f5Ab_LPn7_s zAYlo#<}S8U@9Eq`LCllRB!X{2F;X>6&M?d|8>tQCqh&`vMX_BH|8EBt|84bte=l!3j*$(WA*D zzgB0WceetYUa%CmiC%9I=inUJSRHAqa-fi(Fc zb~iFpUV3q3CaXia&%O7EEw>I_2X!N6}F|x3Dz*QFLw9Z^&!1aoVwgCtv4el1{1h;?nvX z%PiEFr~k$A5ZZ%mISu_xL~1p}(&U^i_&t59IxUP5j?>+3Lo;udYNE+h zwJ);N#WAXPo2-5PD%P|1YVzUatU5)9_TB4+4dHzG)h5PTbZhN)ih<~h89~HB<5{mT zGPC_ikXHT;PRobC6?f-ptwOf5RNKW3OTPw}%VLW~ z%F1O}nCp9S1}#d!!BH-dAi+}imA05i)%4_GBIguwF^SHP?ec6Z(n~_3?7lN5jNjgt zZ^Un$>A?CK?aUI^84X@mj>1COV|`<^Bpalk#ysa@1k5}l?qX!uSi{pFZsoU@<#uZ; z6(e8~Ezs>y*~Yh%?qg798;eKMers-bdPOK@_l@0a$}2m@8t2U0zOl0CoYZQ%{<>xG zvARjs>#Wn$`>2Z$2!am*&2Vl|>^$oqNDESgf?XUL=*Cvafu3>S)Zg2I%A~e|QXgUv z|ETDn@@@=Bp~9nyQsTUn1zUtPf5_@N^pzVP{TT@!$``@OZwsC@zW^p;1T^}00xkt# zQ@o8Fz5MsA_ar0%U!Z=^c9`ods0}w@4Zm@Q(_pUxZp+*4(17?;z>mY~;l7kl!MRX@ zE&h!VJOPU>^)9h+NAmwy+%GG6=sEx)hyLXD@mGQP)5h#`_us^;G>=QlDd}Bvwh43M{pC@zIRZRr6@K`P%UV?|w56 zjJP(x2JKG3R}WgIdcv9!*q#4HX|M@7DnqwSto=8bGl`aHL0o)+dCJ$q>HHq?C$mRavI>!OY z*M4mtNxVah4kOj{Pw#mv*kwR{|~?{m(o~ zpFcR#Stu}LuD0<~?BME2XaegCF*1923E2AV(*Ma#5W6yuL2Xv38#tj^DTQ+HhCc16oAz0^omXj zC(_|D+0ta!BuZh?p8AL}ScE&&gmGm7fp8&tqlWxPhw0Q3qEdk7K2*;(eug`%5qKpt zM&agvW4hmVZw~?vJ7c>{hREWUuehxb(Tm@0*jO6SJ;JFdJe@P2W!N?|6f92Xxl*r- zWLS?$JeNNbq|<&TuE6U3n&`mxISm8?F#dE>)P41rz+5F6NiVAFz0nhzHOR7Wiea%m z)-pG1uvo0XShU?BF8y-3mj%HBq|pkB|1ZQHh)Ce~u{#kY!8Ts1U2KjuIL zj~@JQHZn@${dG)Q8oL;*CG+0Nu_>b;a;GAuVyzNa2d%pm_*}-HpU29lxI(4YpEWEX zEKNqob^OipWZCAVzh=PggL%RP;p+#=R~ILTthcb%^*s^xbczc=sWdz6_BT}gPbQ@g zFVsCW%sq@nA-Z$gc`OP^*&>-lgl7td&if9=xE~tE=%E>|cj;tX^%c#>cGY@xKP!bI zv#_cai)QCzO0HKo7xvMUp-7&;>v`ZkZAH_MU@hmsi}wys>kXJT@y$;{a*}}MEB`ql(qyQ|YL~n?vBP^Eha#VL$mRAsC&7>>|8a@; zBo@KzOf=-|boC7ImG|-YM_Rz#OOpTb-gxhzAgXGeh&0Uo*%v+py%euQ9G?3E9RKc* z8D&r^0Xyo-!~SO&j6eGjzG8Tg`jHo0j?y1^AIEC~PPi@VH~RB?S_!0O8vmRjZQ>~? z7epFmmQ24z4+Y8aS3Qv_C9`QApBvzeC1?D47}KGGbYkRMbW|6+EV!0b6Cs3Ao`jlz za{-2R2bqVV{$h3SH17{+xg0+jrk+`{^g@kyy|tjw?)j}Udd;}v^VN=}8DE_KbQE|A z0beKYy_5adR`KSM0*OqFul`eD-h?`S4{KRAL*sh)yt_}d#_B~6vngl28;`H^Pw9XI zM!&H^j!6-+IV-jcCqcki zL5|p$JK~TFAcEL$>;AnO5ET_I9?8>PugbMqU$>4RSPC3r9V9Cg;VFHN$^mpo^}==` z2kD&-3NZQc_kjaI4jF=|K-ua16A(38Y5PoL`E162P}yj@n0C~R235_a;HTNRymy5r zlytrA@>30n6AeXE^A2c}5?Ub8cRi%6kfr)u5A={|3A2xSVA4b~nMtgJs>brd^O&hh ztTm5;AM)O=Jkfyg+i8hNA~oH=j#lq3%v`ZTUWn}4VUip*>pIbH8soZBda0p|*^v#y zCM|{T)i{`!2CJ}cZ^#KY)X!?VzGFkLp}Qa{k=0ESmO9qK(&@om$}?TC++AALZ8K&k zJTzF#cpVo>A48E+(^+4TV@d~JM9crE>`f4sTk(9?$Y6%c9gLkGqb31^t@A8b!t=iB z%-hmkX-YgtbSxJy=K_XC9;XX_Xm-5F_@kOjl$Jn zU}s~&XazQ0M!)g?!eGVx-SmffG5l3e4YM3qEHrz0O|-OLL`Sb~bgm97b2)Ck&~PV1 zbzHwG4rC@H>WEEr-O*M7_W+^$@whpm?>SI1ok_j5w^1i5TUjIMDL=P%-AYJ1Zm7sk zZx*nD37Zm+qp=KNUb22%Wp{?ol;=4GF#U%a(s8&7)J;yNIPKuYNu;Z>yoze@B@%_k zw^v{z=|4ZB((TLFL6;V{=U=?LHe$7AI@`1dnBuAGKJtj zfwUxS{x`;b`z%;195Z+okkkDH3Mr|xA9shP)k}ssB$)@6m%z%V+(@i&T#Hn@;41x8 zT;u(5lr=kkPj1(};cvb8Jp}BFHgN1y-xcv$E!; ze6eK*J$nzmUM7>%R{xUrKOG=n^dyf$9t6ApU4;Gr)9Ro9ladhL21EFlQ~jfE2TzA6 zXO`HG)CtUgVjMym3?6FDC4sY0HTdsd)e9=^-go)h5EoPjmgjfY^Uq6w`Mr8-@&d%c zLbw0>tpDG9HD8L}S|ES_!x&+wY6yR$tm1J|x&ONGW_^!cYrDNp9Zozu)RBItiv8|Z zH+#Mh$w*GaMB_E+jPWmE!6?i|auKi_GlBM;UVnwsu z*Rb<(5X>TX6rhBXxNb81=}DXYh{pcI?3vK#h}*OpL@PW9JsfP}V+k_BK}#jG?q9xs zy}2+)oM)k+5pe_txqs_&hTCrmxw(tw13tBru5Lii+y5A?ggla%XKnX{(0r(hLKo?o zWP{s&%B9xxt4LRhHpcOpPYm>Fmc3ic&^O_}!*8bHg;WB&;pzaCz&OPxWoR94ub__^ zvTV^Xd4`U8LTBULcM{KnLD6Xcb!bT z8XIFXR4p~X^bI2ETP*3;^5U7_4n39YHBM^-&H7vgGOn8d1k z#7%Lo_S!W)`&eEZ#!>?}`RY4b-S1jS#QW|?E=9`FyXO?|UuwOj$WG8vOJcpbF|Z{n zwmBDEL&OqIT5ElNeWl5hLwuHg<&%v5=;s$BA=xKB0zz{+OU#`~ycG?dDRmVN^GkZ~ zBW&kC26?VTcs_#r6D@OIByJ3OR(%>C7m@zdtFdu!ZzZ*(jLN_SY5&KdDmkS*yGe{1 zQXcw2BtMFF>^AGW9En`^V9@d0SX|zi_0;Wu_kDe#DMS5RM_1V_-UM?dl>XETZH-p^ z_(gGRk+B) zVR393KW0QCu+V!G6a60zivyYS%1A_gMPHXmoVHE<1Hi<&pBrk1GR4cPILD!93LU89 zf{0qLGZ3Aocl%j^Tthv*66h1F3stq@NW+W~0y^h-8gtMDOb>~NE0!x{$>(5RPh3Dx z8QPs~eblngs*M|cXWe;jP|dmGsgBP?L(1%9DIRh9dQ1+=>;)M=8;0wIF7KQAFQe!e zZfd&6g3fqGFsJ08J(PXhBT4_f3jkVZEkZ42Lrn}m+$Z9KtT(pdod+Z@k*U2Y0aSTNobw;UJ2k0ng=zg4I!i zrM^=8nXmNXRN{qG-wsa2H1$z2DsH;1xXIS%6nqbg8hl^KQaP!(ak129^Mm^(m$!Y3 zOC>ZN4KDck~@&R9v%lp?*qzec!J^t9|w|sih-z&sRpG>LpQTg}f>y z8)465QJB6go|*NppO)Rs#zKcBNv++c77NVVJ8^G~cRDLZZ@wf>VAptM)O|Q>JUC$J zIj%{`kK?e)OtDqw04Oise^g*fZV22%zF=&s_Xkp=BD^POJvoeZHUdmvEF^S#Y`v1q zJNYOmE$f%v&=Bhz^1cxqbQ`w7d^P!IdWldeudQ)!I9>BOq{5vo;EWbV<1O)`p^eYXttX6d09A3=bSl0L3Q$o%;V$Lj(ONOT&H^q{sGp8Vs5 zeUUuC9y=4ACNXrNr}o2SUctP3Qca`qCXIOEax+OOoAy!5e7AFn?uEs?!s#1r^>b;& zXR3qp-f$UrtJd{IXk|}5Se}szJ94Q{y~ucY(;}T+dm-&$2hG>y+9OC-4aKTP_LU1Q ze?38hBIqo_t|`6li9Xm7#!nKEv58pf*ejwEwbV56N)TQ+R09vsdI zYx|~qQjpz>HCOXz0?W{h6oI(&`zG|oFV`Sy(?@_daGw9zV)v(iwH95q_}ozu3u`)bod&`h`rWx@{>lSI zZ9^>{s^62-{fDqKXclpp^tx-+Ur+ib+J4o2c<>$h$WP-)ps zzItx6(m*iF>u?R_VQX`HIrX_uhx2xe6q4j2J*M{tl}_Q$A4fT%w2!I=iL-`o4O)Z0 zauRV-)e?DQV%m2!rEIJ4xy$0b?aw~V%o39!QLY6^3Te%ikBq9%#6)aePfZFxzXr!O zj>zLKnasV}zox(bZL5eYsBAQD@YSuN*#y8*G!2&DMmQC={4S+Wc&JA#==`aJorheD z6(gV_;#G{-gTB~Lue;ftG?aIfNJHa9l|fW^b*hd^CQ3VtsXA_Paiao@{pvq0xkXYD z)Fx~2`E$n8d~S8n7TF5y(?N2l5FRMIAc?pg)T{p0(K-3L*hv+Q>g%SPhEUqVb9rm< zvutVKh{A$_!@17%p95Li>2rUi>2C5py)`8=8UJ%3etPIJU-Y20VnOD*W)!R|ttgJy5(6t=+9MVJ0GP{WKV-Bu+D9ysc# zx7`h*9nvIuPN^84M$zeokr3BLzWgfffsM<*dfi@|;0p^~tlScrx_>pim`O9dH-CKd zd5e+5QpHAY*g{10yJ_((%0w3Z@e)1E{yLl^M0o`FZhr^F1pl}ntkR6YcqhsA>+3X! zcuaJ3R!Mp|bZ=2qhgxtvBFpckjBsP`a>p#lX7-)?j@(>wsu{fL6aeBfkwpe`3Q;Xd046|$@iN`&|w|8>b3Qo0e z8rnQ{;_l7nveI?C!&b~Sp8KofNyh+%XR(#SQe!bINJNV$A)sd&C0LE(wHXX@yVxF= zRxjnRo|WU!7DcNUU>~tt_>^YmE1tykxesC6<`i|G>ulmJTt}mN{9oUy`wKXT2jI_< zPb0k{TY{0GM_9$PEQbW!hC9TLKVWC2MZToV=RUAVOKniwOH$Q=NkzX9bubs{biDgW zPPU#e3p+hqea;fALsK^*{a%$~GNTz<{lU}b7^;G(Td#N@bo6vkp8GJu{F|2-^uTA|d#m-_&P)18o|Bl9$zzd~1za)?{2pSD zoOi!Yg{=8Zziw-E$Qs@fVJ|IRZ|2ZQ)Fva@7!|ge;re()bo?rEt!U;F5?N*I@91>a z#vQ@(@k1=jiuq;lj+!ap5X!GdkD7E;zSS+xs&~^y$BtQ~vvC#b;a z>ADyji4+-Y7x!-}R6ZFR%Aqo;RKIoRndfA-%FGmW-@B%O=sz$O4cvqfyI<+$4PJ*>qw}Pk zEMVL>{>_WLm=9m>%2lnTDC=`iDDF}npv%|hXSG_hW~u7HdP;n5eUM-2x&G@tF8Xc< zicsjU?vR5B!0Pr${w~}U?n(H&G)tVfh8>?yg*q)&4S0zQzYrbj(Cf%k)gNk)$%4C! zrqBr~Csh4@>Ll6Z@AsJS0yuciw84V*139@Fxj?vo(soY;}# z6Lg;LGup+=9nJm8Pk`Yl?EbsRQjTS<4u3xxy-m3 zZ(4zcMn|%bek8$=L93qoJ|7DU#h%7R>#pfxM6I+h2yqO=nd@c^H!iQ02{TI1EDy}p z({CEMEshe99726(x14LKPo#0y4FEh+(jJy0~1Bof)7E7?Yd2nEAU)XrOqj^MhK+ zLK0VrZ;ur*TslVs@aC0>l*Em?fv+Yw}fmuaCf$f(6%xp&gQC0bjK3^sn-n4z6V^8@x9=TBTA)*s+35=%b z!QU-h<7>`oKGU6xx7o~NPFfGFXs!PmtkawlahQC=1-*{+=U1QurdnLL*HH$cktNAPrkJo+I*?)xm8_Yr7(@{ zP$(itk)+O~BY5i*7%P>YUieoh%mYYsDbin`X+?T_C@B2^GMzc~iLDa?Be$`P;NT3= z0_$kifkKW_C!1+(`%E-==35^S|HO;DR?5Y~dh{L%4~=t`1KMl; zKCypw`+S1ir^3O?^~Rq;G#eKW%YOK5rY_7ATSnOJx1DDH{A}*Dd>wjLZp@h78hHKIs zDYX0rliNZt)#$J?A><4wY`-gB&va8S`B=2;H6~=1RqXQ0QYqkDFVb^ImuLt(PB z50R$#Aq0y&$|wzW2AUfo>Mss>N#Y}~GIO3x%iqRBw*-Ircheq4bu@AZ#A2tq$b_9{ z*gP{W=eN#HtUwDDJetv5zIotU2lsM0HpPn32Dbz12z_)v-trQp(4PR(Wn z5u`_oeVbgvC}sA=g)G2Po-LK&@R^1(JDA?*H`XT%MLr_E5KlS}=JEJC3Ga6}adrQr z8ai|;jd9u5#w@2FN$qtEORV#0c)3ln?YE7Il#K9?{szIK7dPuYS2#zMlN{*6XNZPX z7*;I(;A(@&_LchOxuNmKo8TB^SrRxAb-=c&)Ls-&LX;=eM# zq&<&fy5k7{X}UCz`)j!Hsz-8cbR3_B$_l}$+>?*Me;a~v)&~2O#-h#rt>Uw8kx)4M zF%${q=Ld*LH)kM>81A4qX^ifg9oABcDF-KbYcp7>!qLGh{Y>+x{k7-c!7=ilQHWOC ze5pKkf~fXjitg5G$DEVrl9Ns69lvKuA?tdqMCD;+25|jwJ<^vf5M_wMdv_Fh^Pb4B zX34qIrIHMqekN9xu#BaCH0S1`?iL?M!8h-UjqL1y0kzhafmsO$R#|({20h{IZyeJ` zEO9hsr%~Lu<&Cs^ZZWL9G@Van(Y(%d$>^AdqemYI*a-b&$IYK-y1expBKeT3A-4Bi zkX9BQq2yVpT+X$n*&I`2*=IH{`53m9z3!x7n?3C3>NMc)q-Fm_YNU)&I5 zg}Lwp;-A8T4NOPP2kZX!K#URg!}8o!i^w#z8wd%)U;g4`M@@IG zg+YI@%eYW8(szwF0q^ihr?%V_I)NI?F#dmNd(Wt-nyp({f&>+iEEx%sK|q3%1<4u7 zNt>k7WXX~Rq{&J~auOvqNRtJL3J8h_4NVRrLW5+G^wpNcN` zZ9SOvzE<^|vRkVMVrhV<+3MJ6Aj_T>NL!l<($H-B9_O>rMBDRfjSJRstTFdgC#a?8 z%dv~bA(K%3Mqd5lYY)C0??L0h$ltPP!qaRUrGOa+<^TP23iyw!aq>j;J@8kFP1_KE;t*T@$7b#Yf!&x4Q zB(Q^RgS!FRo)rQ1Wv1VYXnq4JD`C3$`otW3mDW({joGJ^yeBz5;3&nyXs@;JVls3r z`SqcrQtq=qMK65Kb8HWM}wC2O}1rj5NIZ{?VY4cO5kSu36K zbhFSs%>m2b^IY>>sZ2)--v*Y}ViLK6-bp8=q&x)wFVSV^q4R7s=eN_7`J?c|&`tfO zm39A{6`7*QrGyr)&u`?bOT4Nb++E&32ITe7!_D;^+b*xc!sD8(!R|yB0!E1fBn#p=o6Od>8j2 zp$B31f+E-8aCfBa#714QGj}y9}tR-8BFyO zR5OyD+DEUreJcxN86QP%WJ?}Hgw9)~zPAjpuPn4Z!diypFUm{ggFyVZCIDDBTk&J) zx$ab8ch3Mn{~njo^xkZUyeGvKE~5FjYPgZ8kOVb)bWfpw|EEyC-9S9-@Hm=u>=DN; zRQJ$eY*WIV22j3x=tH`jIfaD~cWq0P118SL=i}1cQKgVjZ6-~h zl@&Fu*0$SoOZD%ItoR6!yTEvJo<1S*3ik~v{1|zY>&=Wqf7+Mnq6TR&q}Hefyq0*O zfFD1h@@d;ymvRBAdrp;FkQ{C-?*^SAAc2m|C)~c#ejS_$)ID#*ngE^tW^nL+$Q<(a zz1ONAFHP)A8maYtkE4aTkJN3q^06sGU2la_Q|)_dTm5dn^L*cl{(`#Et$C>Kd-&Wj zrRDN;%a6}aVO}W}bPcB&jvAv+-n5HRJO8*G5_lf;cTZ}T-V&@&a@$e{KGauJD3SPY zbcHGR(gHIiumE+I|5+mQ2V24|wBQbMC3(rlW~DGq8a0IYsbAIdmI@wZXI<6u167OM zzQ`iwTDHQwCfLE#I#F}qw_o}`;GvB22O8WACxX6hXQ%q;utJqesLcVB(qQ-qXwC|U zPKBXkH^~)1pr!8ym3oK;{Hk-zts9-(K%}5Y5XPDi1-?URFY%BqDB`&q<$rSD z-onS`Vcn{}{BZ$ST~9ubiYGB@sZ%j?E#89;v_g&Uz(*M%QsPOvPw~%MkDu@4TD{-R1}l_Z8zgzO1q4RBFE+JOzldP6=$ag= zW;JqZl~Ttzvuu8IVp-D&V#EZwkLCIMunhHr5||)RI+S?*IQ(AIbM;0W$hJYB-WZi5 zpuz(nTbKo<**O92n$!ojV_iVec!flpV~3%@tsz@J5WxL|@~lLOVtE;mo61_5V^Pkg zk+^0cSl;;V=3PGr~7QcKdsZS_V6_8JK^Uo;3v@l%B*=vtuFg>w{;Mhf z!ffY*1nJN&#~XFbi@PS(lTKZ`p)6gyO|+)SNu@zsnGztBC;=I^C8N@0=$%h{06)!O z*a%1mwJu>O?ttVE&wsB65XXx`D$QvJy{_G>>ZFArek{?u$ikc+ zR}KU3d?zK4>;fpl^V%omUK3k%7{EIZh`{(NCglkeT!oDB%K3kk4^R;$9_9tP$wsyc z#vr2!i+0EVj-(b%?zC9>Q%%6J3v8e2fTK&k`&;fBdTsjE5OpY4oi`4kh`&we<1;ujhL`*^Fbhy3J@V6lqUBw@1?I&T&`$$X&G*;2(az|h zD_24?E@MKhCbkP5*@03V7h8Gz7=*=3U&t^^D#X%_S{2}c^lC56%q>Q0tSG6WHQk1CF=Tt zOw=*vGzqn5YH{B`=Y2cq4xdj|%e}+gJ7Se!4Lo3KHmVBv-2Ub?r)4iB?se~0K&wI+ zzSaYIocH3N@8LbVz!jn`pT`w7Nd}L6%KZ5qy2$u>ImAjhYs0)|k&|AGmoN$gfAs9;pl1*zPVIR^>3RRsJ^N4Dx zg^nm{X2bU`vOIY=b04upcKnH#$`(;Nam=8~8=}e+NLpgW-*E%U_A&M%+I*Kt9TjDi z9LwGp6y_~Xg)hy%8?g*v*}QF4?p-WnuFBWUr=+@;0v z-Br9qDhvVZ^4&c2NC+(V84Pod!{{m~LldIFCXbX+ox%E;BAle`!vomBhd30jxH!Ol zjJ;)|yZI)TM2{Tgp0#H_yq?lx^%u;||0Q^2Qf57L_+ih-^{wf*g-2@Yy=E^PcRe(t ztIE_^Q>@k6xN+*9VRyULW3n5RnY{GW$Ym!CqG<-u;=e_%=*GkR&rx)ok0fL12KCWE zWt6)e!Xnf>D7#lUR2cV(D|ettjbfEYW)bz0HV|~76e+r#pMxPhM~sdOE<^8Ty-^rX z;_U7&AgY_A)#lEW-$gi)fAgfLK3%ptlB|jgEiOu;bKLk|SqEFYQc+a-z8#d9tXF^& z3N6);y0mzb*$)Q3_EsF>>y0S;LW3_t_FN+|&4ETRR20>b7-gZ2WJ=emuc5-seyDnh zuNsU`kaMnUcV?+gTqYNd(&9yvLu15>6G@&xjWHtGnoB2W{`Q#O_*UyVXS!H_5BvLG zM%P}wEobZZdW-*32qmU*z|C@{{O}WX(saN%#dRhs6*4Vn||Q% zzuWQ%`u-0ddgSZ%Gowlw1TL}!>;Qsume;M>~yh@snN-6pnibthgbHHrmjagCTA zwP5JGs%<*Ku*}M*wrn#GkdyOW11xcE2L7FaAgK&B=wrvS-8#%4UWpF%{u)lBvnGa(bsWgk}Ct|qaX$@~5>^o&1 zT>ZSd%|ZXcIwZhc9OkyRFYiHos*cQZU1(+{?u?apP$6t|o{)d^h<9j61(x=nY^qU8 z%C%vOU}$J4ss0A%z`c7D%Iy(qZFKnDsH{Y;-648hZ5oVI5AXFgjGU2tA#2e#wMC^_ znc$crlIhSf3}&8vwF|{4g>bs*9P?)(NRa2E#S=fpMLde>HK*gu$KSy=CB6~GX*!&{ z`oy~(_bE3vcX#AlcF*_lbOpO8zuU+x?xAK<;?8*am5tP2FJg6IIv>a~o^NJxo12D~ zRb_s#RQ^E+NFf)n`E8+)Lfo0V$Vrd+8%Crp zv{Fg%qC%>fPZ}yopA3&n3(#@LoSI01!33Cj924lSgmNO}T{3~0FnlVmJg@Opnut5c z(?33Md$v>+dvv9B@=!W^xR+Ju{J3^X-d=$FI<=t9N(|EH+Vw9@g%qEtHH3xBFP@&R zx$~O{Ou?cf32T=akk>^wYB+dM$8k?%Z%5+&|+^f|f?W%w-k+ zSNp}>6CZ53i{R1uz35?R(^O4k{cF1`x~I;jz4==}dAa{QuK3`(wb8;{-cDN8z39^? zAGLkFg~E&kYPqrgewZGF*~BZWS5q`&qxW!0xlxqo(o zJ|e2QM%JU^a(n?OZq3G6`F@#%*t>{T{|-ENplgs3!5K0*qRy*(3Mal+_sZLSqGd;m&}&OfD_>fV`dVjZBU!qcyeG&V4an!o7$t*OSK$+YaU@^q z@_P=ffb~DDp!fS7c!n?zL-JnJ!D5eY-TeyZyB#C2h4c0rDXVuz*SKb^oiUNADaEsD zo{e=PHu~v_Ek12At43uy=|ru+1rJ; z_<*`z*O-PsS1LpI7OzUnj@e`6tJidd>NUetzXw{Lz6JB)Z*@0(7q94ZAl&;w01gd& zLuXM?ZX|*v#2CQ1Jz^%2j zU!)(%Ilf|aKB_>THUmY=?ob=V{Bhu`75_y`K~`O1ZEGIXJbucj=km?O`x&|kDFr91 zrSNT-;ci=Nn-o2Y&mVt#%J8}Mc^Au4zfo0<9ep38*Ex-O>QMqDvEPm?w#t0*Vh0Cx z_9r&cBXDE@CKGP z)e_vKOns$+vtT@2P{D7!_c}`plbAS9tHZaOt-M2dymGQkU}B+)bQ0DTSHUIba8))P zc+e=a@f)rqc5TJd_;5?j)M%l(x=i)jE#wK``EX)qtQdGHtr{Qzs+ia3#A8hr?vBQ2gkQN#)(j zB&@xHc!d;Ho6vw*&Al~iuvJz9&%LGUKrr~`V{Yq-u- zm`{dsoiQcHFn>%GU+<*Ocz8qEN5L+X7~>s2;JNtae*a*x}b7(FpMO5S@#VR0al?eyC7JG}%b!Xy%SGN&ej8YyrMzGTdONSL&| z&hoih!?Z%Ftm`So4c?Vg2ag>*siKqsBrzDdOpee=RU#Y-1h%{PPFh2;Q5I4QDX=H9 zdGG}NFCemlJWLOONCgsoF$7itcd!pKDR~MC0Eu{)CmpK9J#YEdit{pH4(D zPRhqg?ueYX*YQh|7>OMe8qV>3Xqcloo`)vIX)ocJp~szk#iP~roaqFoyi_KBiI(>w z;z8hdrA7^24&-Uz1^lkNge1lC8_F7pf~`GK$Pyh;bq{Wt+6HAlZM{S z-F<>bWAEOJA{puxM8|;D^ogQcRfXFZ_@ zF#-LR>PQkyDw|7fy_U7_g7Mt#N#52Qo2fGs8i>1oLvpE2>giY$dS{ePWVQ0%t0}QY zjotR9Lt+khE3g7w+V{ipEtGO=o%ycO$j-AQIxuCNI*I-c#DCZ+j@$R*M~tPEjntea z*DWMJTZrvdfF=0Tze}D6Q`|6$1MLwl+z2Nb-d&yoG)hMhP5B3oNr7Ho5uMPrL^LP2 z?CsGS&OQ0WYdgg_@v72}c1XJKTf5ldz}!LCi!i=z*{{wbAH`6f z%*j9Os4!pX=*kt4PD#Tv!v$z&#<3QP#*Lz!PHTMM&uaihP zH9XfSmX#-eujjk=>Dg`Hd9cka@5ScA>2}$}ORRwyU~BJ_7f#z?jnY9;Truq(WVuS0 zEa=_t$MgQTp#|y;V3|PjtoCqO5RnGz#+xsk$vssb-zKUUWFCck2HuhR+3W6EIsWA> zQ-QnDo25-Y2E967^E#{M3t-#0lY)IN&qn-set&l{ZL~>x2$8k(%BuKOl(0Sqd)@|V zCb?22ijvZ^ObAKNCsn6Hwt(F(ae1MZQ85^X5iW(P2mtILK$r+N`b;Y-Fm%+1NqTS$ z7wsxBG+OmpU^tgA@#*`Qv(@@bAS{qIdWp(<_>W7fy}Xpy$H#iif2Jh0h6Uf z@bK`B!gx(GDZM^;9~H(v3MqRQ3G;&qHdqKP+RX?kN#3b0p?fgPh8jo!Mzr-zIKvSLm?r{w0@#2i! zEX%2z*rRW)GI(wW+|#CUt(M}(-V{c;DT$R-7-eoG=~?fofgzI^46Cz~@y54=73#@LTR&}EbN?#%gv;UP zQP37QOK+_h>?AFLZt`mR77xgTfJw0Z^u#?b6J{>B4vctWJ0J3RS9qFYEH!%ay$3=A zgB_R##Nnh>VZ$_Sr`WcJ}DwNLY@82$=$ncdt(kie*PSCnjNo|LZYfK zeZA{Zcz0PcE>v$TSJ2>%v}Ii-T_%k~X`R34OR1-e1~hGzEy<{Oi?#^d`5}usJc@8C z48`Xww{cOdpYzJXWL|qS!P%L5Ra)vu8(K2utz_R(+brz_R$XhCIrzmbSDqnO<72cc z6Z?}ZW+D%^@ViVAcMUK(*mp18m1c?SwcxEFO9jp!;X_xC1%9S^nTJN5gSk*b+i9(a zb^a^Ho|Ea*i!~xDc`NOQK6aQ#WfLQZqdyS=KVDm{=HOp-<3TtPKez<(95@sSfaq`{ zGLNi&KhAwh;HVxDzo|3t-~RS8f1Fa0hnSc0@~W<}QADV2X}ySe8*b1h+s)VV8(Ep}q$68w&#%t_>s?9wC0++PX! zw*df+JU44#OzE15mUUksT5I0Yo&ZNL+&(dMp*($fP@E>e&8lvEns3z*YQ=T(v?H=Q z(D#*VF!GfvUE@rSx50X*F$5S&O~&cMS77(A{xLmyMhMr2j>k4?P2ZXAZhPX0r;zRb zQmz3fUBR&FOVvs%yGw(zv*W;0QANvAs%PuV7%n)2DK-*k)(E+i^kmFML+YRI=dFFJC5A*1*Gtn?80VtzH zFqt%(2j{=}+S^9WZmh9l@&oBAEp^fI=dUl3OzKYu&-jqJJHaq1D_bTszdH zQB@Gu78q*N=6D7@=fS@`C)M)?yysQ(w-ZD*s5Km2nhXuJXO3<_w#R0Gb08S2S;)kM??U;pRDL zz5J6J^c_+cQ7#x6DUQ5BnmnhDbKpu5jREGPrn-9DU;CdG^BI%_h85;VzJ z>cLQm_HtfBdz>}-o)fT*^+&!tod7nb%mbMD4-?z2_8=U!QU8)Mg}8(EUoG+3KWX}W zFzW`lw0g?)>BNB3Fcxi@!PN5px)?XABly1XnJ-=h?=GP7bAo^em6a*A``5&~5^ryB z%O5dk-FQe5LGoh4sc+`8Rlttn!r~&35)%`!o5bRmfvyPjy!h*-yn+#AT7;+64kwI0 z%tt%7oIAW(%%5$*UVIoJpmJE)85kB+2sm_Jh#MYp=_;n9L?Vry*QK#t)eo1)FGR%i zphyZ}ch27N3b48!qR(2hR2b*pYdyDd6N#Sy#g3%sPb&L?mr+ScNgtAZQ^00q1p4lj z99Ot{sS9N>4w$m~$GoGr$?$#P&L(+WTY!KMMZt%kVK1vWc`(Md_;%fl;-kWJ= zBsNh6&%T`oS4V&qNG1OF%AjZ{Ge{hvYZ;=yBlX4e9^Gy4r;_hV&uxh_8!}v|vrt=j zvp?w0L&2V85_z^$UI6aQNcXWC0~JP4jU!S4mjLp_!JWJu_YA;7?wkG&i@QXN~^LvxK&?N)^VpIWrK< z3rq0?6^vbap9qquRRnX(?ll)@Hz@w`?3sTaAfF9JLt1L|jy}9eu!!+8@l&uAm}p3J zK#Br92_t)_Vx1M3B;p??xuPd*G~&B<`Q+sAVwEC$^&xw7RizstjYIsh&~wRrbV_jd zrClnw)5{N9`@?3k|D5Yy6W?1P1}Ig66>apFr&h#CEAld$G;1n_2g=Tyfl$T zcb?^;8*$w^1XtRLv7G$c{^#-rSgT-{*XpIQ+i>v3#eG0R|FxCCazqeLhYO)Hf3|}< z;HSL&BeY`TA@anC6DJb-zz26Mz??#IOP{A$uA!jPg*q0?-3LnDd^3LV9z;?A$SG+; z&HnoDn>{4|AsIKPx25}L*|dlaWvmBxeD>?J0Mwd@+CTjvBA^#6mlqdz0cr(gy*998 zESK>ApSn?$>hYrdQYZ!#Q%2%(LUeog3(pQBfZX=zTH2=3jILAY}F0bd;vOBcZ!OW?pdy(D}#5Y6A z+OeTtIaMkK97`mo)>#B7BbjJt;KKy?6r3nZvAYN-N7ch8va8drEEj17JIm{)9%&Wa zHv=33UiY;wu=3RKn-m~Fpe7Hz3h{IJ<7WV?t09?*B|*{#wdL`F933YAhml*;ld4%$ zl@hlbVe`Dug_5c6uJ#Pr29a!w!f8g%J@a$*`oJci*^v2bQ2%ir#OUhdZL^*E|!2wR8a;r z(|HcIwyb=7eD7%QuYlQX#P4KzYE@}WZB{qwmH9ie=aa;AnYn~n-h-9B*3*EukH`lv zBC|3x8IYtp&x5mwEm{LDkFzO6ha<>XDgt#(Yl$Zp=goz^rbJI>E76e*-=eR+GcUi4 z(bCca#2NW_kZoh>Tz@S4JS=#>N+14qAJh+E7ZA`2D38{no!GSA#WVaz2SMw>y^!i9wh2kKei>Y z{{oVU>jr$p4*%WJrpAs8a{qXvMDCb)&im>9%(Y);EH~W?e;+Cyks^QMWu3c?z@8)a z52Rkdin}gQVbwCe=b@Xlx4k_RC$**T+{&A^)iZbYIq}h22$Hd z@fmqgUGOAuE%SIt&YRzDVkpaGZPIQW{LaY7b4FUiP1+M){3++jMc+V`5SRdl;FdjD zptPuWRXFCgH~EwoKiYAd({sEYNaw!?119`-JJi9$*zI@a9|@C zzl@Dl_AU8}*u^L&pYmujr``4G`12QOAJ+vihAi87{0BSfO9LaM5(%nH}3Dh4%ulth7sW6x7I2vDDczpZ=Y4>&>_8%7216T@3Avp0muFKQ2-hwR?3yOy_lHc!uE> zp}Oh>)J^6W=fFi_>^pdjZcFb$4JhkZxCZygpEng36HFgY?fp*4BiA=ytz%vD=^q#% z{T)Dgv9~@NyQcm4t@kW}e&XvV`%)qSCj67J^!^JU$e-1gXT6iH_)xP?$Iya=G(L=z_2dVYzPXP6N))zj=jk&_x9Nic@8Q^a+{Ghx+>hGwaI}%Nb!7#ykofeF z>~^Qu%u$2K(l2m-I4POTc7j{!*RkNx80q~bM?y2i?zb?TsTXN|EsO;ra|hh`omtYL zOn-4Ba$RO`g7U7p4xEq|-?kpjYC*JN!s14W$#OvMEiH2UqP&eqrs9ehQfE@_?6}i& ziYn|_98VSJCs|Qlhj<%#2VrEguLkBu4M6re50Gh3*EWUDD`=Jm&H}FAzW_z>aLAr zg=yrX`O&ykYd+2CV24ez>3nH@ke9f!d$$+2h^&N~{L#r}NBb40Z6-B%blc_|assu5iJ=EZ}@k(7P)}LCOn{kpgSC$>j(; zCPOIH;1}!X!aR^SK7wM76c;9kJpl1nAIfV0C!D>01mcbByhhLz5EzELG-L-zk3@v^0R(zVu>$tDgy1HCrJJN$i09<|XcrT3Q|E>*7TO8Qv$CMYHwSB6K@%zx7 ztY2VK4L{u9da=#eA_XLW3ubqOztz+nnY1$`#~32ef#X6bjlGw*zfpeW@6bUyk*EVP z4MSnO=?P4mz!E57Q$Z`C&!wWH!(oYE}(-8q7mqI z6Crt&;(0*LUPn?uXrVp>pwu^C9i3gNFyDQU;>4X{p!?FVsz2F6p>F?}P6e{b6h1B4 zM5egztEu%sz1Q!F&#}XY=CMY=p_zApSm3{z89*bETw-p_2sZEX(iwetH2KRPsb#BU zYTa}s!D6Er;<@4&ZO?-`AC6|B!fajwVImregKVh&bT$ffHnW;;-h>-vga5&mqAD1C z@Q3<-0Agmxd%r$^!?)l;xx7^AIu$0ClYL#NojC4jeKR~q2<7aAZMz5tL!J!r~wx#u?Wp?(nrUG#7NN3FIMX{7!F=aufA939ZS?Y;)Uz@PLn4X!geMnaJB zy@9t(jEwr6zP|d#ZV~T7T$Bq9fE%+KK*(|s27-aTY6HlDeaerFH@fUvjouYE zf_3(bbzkS6Yr2OaW;9K9Dti|KmvyWof~2`&ObVMr{mceMUpa0N*NpJIZrHzU?E-zv{rF8zn{u+--!7w0Ryn zj>{5tCXBs)1=t;7Sff@Y&{KTvtTI1qbO?M}^hNmdeeipc5~x`RwHY8j?*1T{LI3aJ zEoaiu1Sqf_9Pk8!(h3b8!ap3G8qfnuEnDNN;Q_iw_8V9Yt8c;I&FFWfi_s_tD>UC3 zhvN$dU~~1-o!@5hHixHA7&_h+-)#*LPmvR*U5;R*w2p#FZS?#8#iQ;6NDwDvjdEsz zzSRJLv_na3A$nw}Y6%d8GF$CdknZgq@drTIq&PURR^xp;Ur@FAAor2%&lb-QwWVXl zXwro!Yqfi>#E;)Hw)44IwhPof!I{`S7g!}p+d)vL(R_w?xhch#2rHOe({)WaT|i&zs*c=DuC9cdnWTC8p`43Pc=A zxrdk34N7cOaz7hH?Y?+(UF6qGXl67)U@aaVoy?>O4UX^MgR|K)`A++-e^U|w%qfX+ z+xI20Z`*;MjC8R3L;6~u)_#dVW|g1$ z`eEBt?$LAiqlK~7JMS0JB{u=1`4RsQcsWNb3Ea5X%WBUjjyT_C*hg4D_GF0Bp^M)s z0865D7T3V7VEr6WK~QRtf*;SB1CzQ!l#>{I6U-FYpimwF`t&V|$SXQojCMk!9QyV0Ebrq~yu5^2ZXS=yQtxqg3r zetz&CgcI=R_!hV2O<%N{n7**q9NM7DvwbYE`zj|^58lM_p0S%1G{DU9s~O%-T(1Yu zk@6-5w*g5h$6O&d&ZfeQ%oL$h7SLnCb1~BR-yf!~%S0pxiCv^Cwe&fytGu@pnoI;A zd%Ipn8_m^M=?HkZboPid^Fl)gvRJy@SuuBse?7pVdJj(P9)IefY5Gp30XVqD`Y~4G z`ls?M?|0Hn7OYw8UAHn4JC7cGF^;t#eR^v@9F5es_ZgRJ z(j@haG$ID;RA6AJt5GXWxBkoY&kVC|>DJ2v-+D8XlL3KTVDG^(!;G7yWs;GIw_$+G ztzxc2XCb z#JzHX@h_S$^`~fo%B}K41xgF)BrQ~?202NNnM+{8jlP%uG5kH}E9rky^}18(+byQE zF;09BYXm4V533oZaDMzHq;VUG&5-tB4Fehnf7kl0*HM4G%FDkk zX5Y=gQ`mjD_Q%NVlRjd(sSHNj+Lz9HFwGa^#2Dq0^dTpZM6F0!|cTqJ!y24Oo=EK^ zRZ&wPR_$*1UP&I0k~{jHqgOxCN_eq~prk3g=f;MS-lhUlfH>~{nfF2glHW<~5fyRm z-LdOKt@45+Ep9lOOY!TD>98iU^JD;x+`u1bzKdA?Nty@~&9&*Zm-p}=eAMZsmn;&U zDT)$912_{<`z{n_p_~LASH*&cFg{W++A6 z?R!7nV=ph*NSSF0s;?V#?lF;tY+NXE%k{2IE$%1FZy$ahzW);PGgQxnN86A0OQ3u5 z_BDlD#`fgI9MmAIRH*K)PnH6v^7!wmycXXilyAQk^!|D5iJgFAfehd4Uz;99Y1f(@ zZC%2sFnP8IX9>i%Ww5qv26C&@RYIyiW=?DKl$XofE!yrsX(1uonl1mvFdGy-_a3py zC2Y!b*e^kI>R?*x&genN?+9WlktFyt{CtWBdg2#0Uoo6Nc;mMz^S~%D&S$vfQ%fKH z`3&-+Pp>51aqP|?dxzlEkTjgU!JqmZSQ8;V0!3OK&Rf_ zceHZHnUQYBW?XTnmF3)KEd_N*iW`33>{1c2#sDWQgd6^~aX=}y?>E8`P6Z@>uKoTL z9yUHUux)ka6+JiuXO|zxWpD}@d;Wvz0$6Uz~>#p?p!y%nCo51{~2 zkf8m80+^KW&a$Ir0xNRw;xNA^duU+I?p!V%ARSn~s}sgs`lxelX!QiqtGAM;l~#YR zpjC5eZ6>!@FB|ZqIGy0WZpdTAL0hOt?=3giuhTZu=Vx|jJ3P&rB3@v;wgn|}`@8u~ zLvV}6Yl)}3btI%igm00D87d)VOcs16Z8<)>RS*Z&``{@?M#RZd?>Ez}Tu9wJnc%+d zbW9M_a&l9@XF7iMqwrK1z28k)E}T>-kK-G9vso4lZ2-3>3ou;eVg`9+dDl<~R#f@E z=Q_dcxaf%u+0SG(?S_X-K)`qbRT`eB@%4Ou5-N%F=h4&Rg-$=~bYC%P zZc;}wxwOM`@GnvP81A3a>-1`3Lp7X>Qt$#Y*Q?;=6@!13Izq^x1gy({*!K^&Ux8YN zpRAJX!}~)UEh0ma;Vl}&;pP>cXn=fU-CzP|E_Dfj+c^Jzgr-9!&H8F~MUWAE}Jx-852C&F@-2A-w99i&j>H4qyA3#jkb8;rp>*Y)bnZ0f|csFK$^;z*)}l?|?W00vqy zR`_fUdI8t%w6w}m?*c}LV4&{|=5zuXq1OcY7OprX_Q)an+p{;!LlU0JUs5k0wd9K@ z$ljtH^I-0LyK!~JxlfD?;iTqziTy186adH*Q+#cMsQ|4l?O~O8W}ojsH|P6O%Q2DA zEC~KR3#-1GNT4H$}k;wPKocKg`m2T`Ucp82?xoRQ$WZ{L*^+&_p6YhNivyC=t z2T&#hRJ^vUa8XL0H2>3@ML&~l~SpWZ(Y z{t9MBN+xVz9YB*Oq&IE;xuE}#GxH$?Ofpm24X<>3D$unjbeF_|%^X|;v-^(~B1O}x zsIRX-9Q2*-(>EXv>xr&C+tXITBx6o)s+*AUpeQ3UXxT!lKw};Gv&0ltVxSfC5-y%w zK(v-)|F`XW^uS8fqA0mwKZi@d<7$n7_5j8^YYz^!x67k$K?vIG$uMRMafRATynhqq zT7k{9Y`wVD0?w@siu?_}8bB!Q(TrOQrTHux9}|a%hlj8Qo;e3q5%5N8DZf-ZiqLUN zkxQzq!k|6Mj&$RzIB&pcnQJ9s(;*O+ViFVpG%PeoM!=eV1y8Vnq;_XVM`x}+uVB@(k(eqk}U=Dw(2OzKTM$+G> zPMH5333v`HQ+ud$g#>6)A?*h%5_)i7rm+WC$jH3VEEhvgXLiB+c|M-$sOn_S5A-%I zvmjKr|Kt$Gl>iPD1~ibL+Vtrl?aiG&-`mpY-FV?}N^|~&3PEz8bRIe-PyBjuOAFKO zm$GLh$%nQJG|9k#!V3R~BdMmD%g|FN*xl?9ddK|wWwPC@6AAw86lM#?dC@;P7ioLw zc#hMK;T4I)Ib_0{VIF^n-Cpr{UzHra=s(rj+nNy`Gc0(t@uSaV>%-T}5*mfvOIE(8yfiu~ zr^-O%|Gi5IYz`20I0@E(>+x^T{&Z253Y@cZ97y^qzdpq447c1H8s_Z9K#!I7OBjud8%2(hc`$XL z*zfZwp0^^$e~Y5`dmQo4s#49pUa+MLzkwy6RRh3x9kBd%*>;H2Q)f9;$H>; zMr1Dx%7&TeT+}#QosfRQNyeZDrHaI&hmrGwP+BbC)}1?wbH?$uf?3=xgSXXRq7BFJ z9HPAbQd0&lLPQ86q;{bZQWnPQjgYIRp)2$|cfa~4iU5I;U&*ESX6AG{@w8I3v26ym zJgPiCIL2{Fx4mkC8r;zeqO<>l9Zm>_NUQJZ4dS6NOl|368zWeK7=@28V<(lFevP8E z6Ao8Y34J5q;U76Ko^UC{Uy59sSnv(D1h{gBe14~w%{R9GCyhqw$QEXnz@3_qX+^|Y z&!{j%4R3FO!<^aN|DHRcxDL&PwCJcZ$Rml@GNy$ApeMy`y84=gc;B_6h$P)Kz23Ca z+YA{iCK)jAtNFG36)j^!3`|OdB|BCwL@5fpRT~tk)`jV08}B7ZWP$XoLDIuhCgER1 zlVdrPx4ML0cAi{GIRc@&qm{&e^X^P4xlKE)?$>AzBog_@iPuByED)V;rnZqCS2kp5~{4Cf)r-&Ro|0ydgO44MHbRY5*wfQ_};I#^0d5-l7m%^^*+oTYc2JNFZ=dJ zeE1}3K;gaaaqE1qEfL#p*4jI7jH0k0(@qHPV92>GHNMyU=FLTk$;Xrtq)g++G=A5e z#&1k`j#}n*#rbH1UFzDIL;?%ldj98XcogMmrF9Pg55yZ&k`wblRM7@5-e}LVzj+pS zbP!8w|KYWqoSaB|oTt}-VrJ&#aJ|lja7>g!^*T<@VB{O)%J!9=+s(c-)9iD2xftgr zf&AtRqgop{LkC++9a-Xc1y6oui`XIZ8q1V`bdvR5eCOVa{dW{1YEN_p-c@$WT}_$W zku;^bkl{{u@1p{}Z zrx`*;Yw!H(;aE_Y&0qvMrbuWe$cd-x#+W6$e~(=bRLz+Zo`;x&}T*g=!$sATV)x-%$vP{Qi)?UYKnV9b{@zp{4|}ep9MT^@9=?i zri&$+CFn@_-EM8=Sn6v<|7-RcQF4udamypNtrOt<1uALf78RX0uCP#e^yty_C5@}3 zPh%+UpekL$0ly!2D(aftx+1O&&U&$~89i`z?(T}FH4I^@=TmqF+c@O9V>&d$Fufn~ zd-hRby0M7j!*UEFDtvHXQD)`ykxOP`7elM9u1NPeoQ=HL{o|`sm58y!@zLK)IYAYu zg!J^Nva+&w9t0V&W}LurFLj$9b@cmJ6`4NfIe%x-|JT=6-z(llo^$9{_?->vDhdvroj&Fmzq|S6Kr0uU^y2C_JI8yPhrMPqW^7Doev}a!xqfyuXoVFg%8`FI3W# zCiTtengE~R2Jb!?DwU2X^o8!7PXGg7r zn1HU$=uTal48PS%PQY&Zt#o-+XFg`(D5vQ=jK4>x^DXPxN8K#+M3^*wonJIT@4 z{bNN8%ny$1w!%f>J&eH0- zplck&)#p~ISXx_?xe+Q^Sy?5Noq(Hzz`?%YWeyb~7+?%oM1Rk=AhSbL~teqAh!40^?J{PYXlsPLs3{!t`>IlJs9T8-uvvH;&FGF$H?AkJvAEuf2Nlg#vG_H)eGnTT|>fg50d!$+E>K>QB~Z$j)(s= zNz!loRb!l2V4$pX!(vJWoy2~$x~y>h(hnD+yS zYkY+Zc7W)zeRZtH4XEG<5n4~M-5c0GVV50dG5f9ozq>+xV&sFbIqt;;*Rw11kI=Nr zy=6fljM}4|+_cM>{8!P!{~vpA9Tw%n5fC7sHt5hNgkN zwwtEe6fbb5KKyPV6P1Slf6lLIyWt)zG+TCUa5J0*Ewf5WO1e+}W@(x{YF zC!&znjYj&|%UG~wZFVzwjRftjeCTSKtYCCg)I}GX5xn;%yEI|Xt*GYDHX~SsMC1-3 zbyHRl%5c~Sz2kZTf6f*;_A@BBtjPXM-jEtElFRIwR`*xS;vq8NSidF;p7sXz zC13cvwV46F%!?s7bxN+@4tYF`s&-`B++nJ~jVUSgOsUCp_x&WNUY9x2s1J=&)midn<#l~Pvgu^+E5OGzg9|aO_-!vvzAx21o zCd%WwVpr<);t|&6DO=KIB^v^d^lE=zr6p43>p{JQx(UN=$)mor#(q z|4nG&B!3W82(;s`?Y#T#X)^~W@(PM5#P^n!a>s*OM@A1lm|jliv7sU!udRqTX|Q%pPBB|t95-NE4KyFAx@AmfSqkkv{SVrCG3c`Di;04BE|y*5{3Il0)3VDjv;i}HJnw@i)Q z|K;jh@eLO=KB={M9>wVGe64I&B-m!EXsZd7#{FL8)KGqblXqTv9ASpN;%>?VK{tN* z$$G0IFlAg5pVQAsz@x^yjM>s2ZcF_kCwmlwVRa;xaN%SrcX;^$HLvB7VUD zqaoFKnE%MV|-CCUfgS%jbq{}R9%Hj%Y3#TX(s$I*ZnFXh;9+4 zy%-A!{zSWYVD6HDLAHGaX6QfXr!f!@ea|Vj^oj=P{7znG$U+%ntkqTIHOu z)m3oj-CzBgsQAA#!}5)c;5SdxqcdoaHZ2w^XHtxK%#seG1}KaggGw*Na{hei49I>6 zOs1h>9~R&!$@g2V)4#uz`-TR5VSd_b0m891HS@EFtA2v`1b}AFuK`GSS?c{M%8L>c zF{)zkfrAtk6LV+cG6~q+BLf>o(FtUTD^1|9h)V)p{w;n7i>7oJloir_@_Vq$o0Kd} zglzEa(J_;kfEGk7A&WB`qtaU8)D21F&Fc`~zZSUdzgid|e^1E1X8x_@B@Uj%QK;hI zz`y`pOMEdaJG+^$`oBr%3XWjc>dTEeQc}KSh*|E#e4#Qex1Wp`xb&Za*0s$}@~|X)XDFTAu+qx$O2FX?s6@>Xwk$XUXgOD* zVhyClkcM0Q5A~-U5vUB<@~iZqnyvvxt5!;0j_j@T>$x0lq(Tle#LehS`h|*z`dtEV z4+zwb9?KrZAv{TRcvdK70i*+@D?{=yuLjKdA9=N@7OsI87~{NP_)(dGu3aeNsJBLQ z?D8&q#ZcT)@H*xG@CX<@N!bk~bg)-`1q9|Sz9$`jL+cv}2_5mX4nPguPu7>+vAj37^;VpEv__dLJ4W2K^YHw{XEKpBt${C$BF zCr%t3D6CM_{c)4oQr$Uct?9ZSd*OWdyPx5mdGVmsG#rJ0|0h1`Nuq?2TG!Rdcj?}I zYkrH|0dgb!Bu?O^vi<}ub@FR!^dSd{?vAebEF&(GFYyRo1g_YHFj&GlliV55{i-ScT6aIv;2??|E zDN*dh@7&8lFXmi2`>LxN6mk&F%g?_spkp#1bxt&kqqvIc z;YDy`VFesijV19b4;eZse;7e>_<&0ZdEHkY8G(M=#CEgaJ7s9qYd+~5MAQGUX|9-* zg!2vP*r-j4j3awnPs2+t(mRXA(+i6;%Z7CWf98s!Zo9=M4x2MNY8Xy0%s+$C#Ur~S zk_(*gg;dYw5Z16Va=#P!j3@kG5kI<$Hn)sNpA5!TD07{93cihef=`aUkw7UF%ZL{Y zcPa%Rgnv{pPJ$K*OVidKR_nk{zIZJ*2I zDNJbdFC-RMPaH0A0x=_+r`*xLpiU-7HC1DkwYC*DO-ldf;VGw-0&z*ct7t0xc-zB2 zW_)(SOc@{X^p`YJuJG{Ru@U5M_o?5`gkzgyU{*xId8p`U#fJ{-^u1IOc*H29B zw-x;c7r&PpBdoSptTg?#SAfXvDR?=Z`Nm%DO&4d*uZ1^pRlSen->~DRMtFTdZq-jflcYkxArWM8iNUszmN+hj%0!c5* zao-~eS_$7jSK=0|GOfG!gS!6kUGqHWVG@sR2DZhSV-rBTf@ue z=D;p|CXqQ_nUi2pCvScm7TMnA9J`g%XPdySj#}^7(>ZOi*#5(KXh9+VB1x{-z}Gwa zUgME|%z4NVj7qpjcc>O)cd>VYm9^Qk7L`3w&hB{ThQY91L7z~Cz>Ho(B9;)aWne;s zE|9c*|6`yhXyG}i9h#DYTNB;W9icUd?|X?4c-vj)8f$JV>w-@6M#g$p$||(3)ww8_ zC!0^gUu|a{=x&kNj{PoG(qRGZ`7$gB!D0e|BolKz za?wOikBUKgwZoZL9d*(_Tng3lx$XyGmRVbpTd(7BJx|jyet-Gk6-lARv;B47x#Fn3 z^?l!6jRW(U0Ke>@nf#3E`RJ&oqEja2x$?lO!&8}?(06Ma<(oDvXt~xG zV|A(~R{XCR5ER(DSR>b+i}(yY)iW8|y7 zh#ehrjG1ET9wZJY@ZYfbVInBC9GX>zIER#DmK+vCwa0WbqfHBN=itLR(eFZ5_G(*% z$|mK@EpsqRs!a$7y&1z9a_gSZ@|CsVy;m~7*i-WLI1k>XsNgBD=U>#CJ78)P($XJJ z$DPl-LwJrk&`%0%FPVQ7NwM?=l16Q-E4V?3AgP4kH49ee0$E2WtFZHu(V@T7_IYzBu4Q^oWK3NM9Ls4vP*T*-^_r-<$G^=>&vxV*-`HdJfbW% zApRaRaq59Uw>`fdvO#1ftglg*AO+j(Wa}M{sZG%5d2TrDUSn7rQP>yjb&wbXw^~H) z(go@dPl(h1=yeXp$?HuB0(}qEak?uQ$JZ@Ew?U7S3J-=zmd6@rTjk^+3v1@x>EkNXEJtk7Z0aQkD}7AJLD> ze7(riLQPF$SBk2&QXNW)DNJ$v@u>PT<-i3qVRj|z0LbK=Bzi^;ropJt?oVYvW7Ds6 z;EA#*`hvAC`a-u%9}{9DTBA>a?Ror0>n)XarO%fy%loWWlM$P1OBIu^$pU{#FR$$!;x-)V`Z(i9lrEqj%Ai8 zStXBA@sR*l+u!SF*1cY;1*Mz5A`b?JK-m77)&vDKZ|Ohhoi)R6Cd{{bujFul8P~x% zrFxxNPN;RuIiTi>p@D(-{Z&N`O{mSbr=cm8k(v&4Wz20ZEac~WT^_9~yg zemfMEJ$YdJX->;PTiESqFwXSKl4N?Q#NO(8_T;I97x`{qF6@n;zoTIvzFS0dGRs&IB4u9vbTfVC039GvhOP^fh*(RPyT7T*A9-4Q*BXm#_I@mSx|c z#^=O?kJRlNBmxUn9cm#Qu^3{*eD%~xB0*^&GUW343hvOBQ2*nW(6_5c_HRstP6IV< zd{%4vF&@`Q&756g^(UX@H@ZCipt-|RoI|dNO6sx|8Cc$#??QcYFEIQKcwqE@zc^&m z*VSxkVoL^!!&l>KND%3P}wrQxMFW7!0G4J11F9)usM`P*6 zb1&sptAt#WmvmJv-5fRycA^o6#r@0(Wma(iq{zg3Mk_YeVXzemv0x<$ zqViFEN~dVJ=ROf$u=!Q7dy_53l?a(4vQd$IA3sq``?mb*hBP+EY=D0#_qxEyN-S_R zVPMgUpDF=K;P2x7Q&!2R*RjOs7ZG@iusRVE1%~-c0yOyc&syx4+b_smaM(Rb#V9u|@Tg(G|-id{q! zn%}iQ=Z8VN;zqK2GUXO$k{lwqZhqz}iMVX>7CL!b)5xs9u`>B2>G zn3mQX#_t=^5sVc1mnnAWC_W!vKTMPVE7#b z_}EJyo#Z9(d*mHOEKw6;x$L} zT4aD~GD?XBHH5Zs_`1=oj^SgOs$xL|Y;~q1QSk8_`>M&)EemILD9nT}$6;QAc+G0? zygwK=1r~UUuy@y?y*`0A1Fi54SVAsgz(9 zQ>;JqkJFs2Y(kjqIj)F+nvuki5)$CnTtvb@k%3S6^+S;gP62|5u(YA`$EaZYZ{H*& zx-9Nv*b+hC2Utb)x#8?US}Vc!jxi|Q z{WEzcc=Y;1kaCecQcyf40jrfs zL@^a8USNS@gs3l=?C#a?#LdO^H1vC1TX;WzkCgS9Uqxg!E z8%&_;XSU8wGvT_GFV@Mdei%eN8%nZ~3%sFHzE6b({DJ(VZ7~ojCaLqXl4E<+&X}A= z(x)n#$WdUuDZYsu+EzgspmnIf@a7UCQ%);9A|ht?!>C-;XAhFN2O0Jk39XroAez9_ zc*YcrBQiA;2?Nw1T?sJH6JZzmLA#vBH`fmz)C3+xPgB2k23T$#u}k6QKt4KGviOPC zSh~LszWFrsV9^o%WaUX5_D5@~OxOkmI8sDUA|=Ye8CbqS*D=$P#P|4{^qAvEQnKhX zMW8uAYtwfkGwicO@zej8q<~1lPyRePkyQE~tj_1%lj;kF!xYZwDzDf3TX{e7AAN63 zpF%D(qCvZ7_Z;FXE;P1laDM!OSWzHxO%6;9Y)MIU)8KOq|7<9R-yHlqB};uYDHSj& z;qr=b30Mx?_R_0UU{YifS!amW7#%kx;(}CO4NY19T#lx1L79zwo_Km|2^<$cnVx6l zj+!uVyIDV}tM~=?%X)hHHG8jos9QuWbRsYjVS?wop!g%;zkC@!rS;wPvUkJ_i8*yk zfpv+So31x_YPDO8#|sHGXKhriwzyi7_{<;Kn>zPngK@d)>Nh11k9Y?P+;nDtAZkIp zWRdiBu0ChKbk>4vcgDQllf6x-atq@=<=Oh_8AheMIXc}IXiK0mEtkl#mZQN(b_N4v zz}zYxO>qR*IQaqXbTU}$r2h%L=V@u#0e6$UPc5bu_qE>Ado*o03mYliojD(Fq)NOE>WOZ$?+Zi4^Uk#1a%Z&vcs+ z*uiT}LsNO$`YwCkcYT~qYsdbmYy{Z16GBM}S0@rN#T88(<~-N!+V5;n6y4m^k}Ky| zVn~;BeRQMX``wfR{@NT^a4;^*@cyUpx1bq)5QRC=%d(~^&HvqK*0n9zldTLESv^Y3 z1A_>YR~^u~t(4e$aHPnEF8?Hhw4>3qbGR?;IiI;_-q*b)xs1(NRx}3}a_^!UR+#3c zl&B0W=_!DQkW#Ru$IM60iW!KDB2x55WEs(Y{HU|-C&AGtWYi$Q$0JG}t(IrLKlD3- zbNE;4dcbE>)YxGpy-%YU|A61xvw6;MZcgC!A>?x{$j`uRr;dKSugGFh)Pjqz%z3AF zkc8>!kGxMc_erlf)amvLnQV++h2MFX1G^96$aYk8F4&BjNB^z3FydJiT^g3!yHi#) z<)j1edGq|5tr{ZKXLCfA*QT?zvzNprYh7=8ljKZ<2O%)L>}Re8`w5$27ra_7*~xB@ z4u-+(u+c+KX~U!5s`NhVY>B(M2dS;C`dO7cyP>~CEzIx1u+;BXfyXg>=HIo2A6xSV zxTr6aqvYM~jULJ#4*!Pz^^%(X?M1+dab4Gsh#{Ak!-HBDtfw7prBOT|?CH6>({*0Q zkOJ90@&4)hdWo;-H+L0a^hAkyk6^)3{>K?<0fBTCPSY^bmy)&&f{qdp_a=b7{J>{t zbXJVUxo}oRPfst+!sAovIe%-Ss%vQP6r27C?U(sWX&=Tk^=QlIaz>C$XixUhiz$@Y zfq{W-K#TpzHz^F-@1*HPeATBK-KLs%0*P-sOzFcY6{k@q;8!)AB?rYCd&{m3ebD8A zKiP^hH|p$sJ$77IX&QdZc&`_jtjA4>AEPLmc&Sv_jlwVD2U}flr&x>6;Q@-#ET2ck z@YGjttqvO^LD>nw>903=hBFDmiK8pZO2&%C_qLl&-wSyTjEpSoH1njYfcA9*HOn=N z-|_-DKIkyx0&c`}RF?K`-`5!a{$nqfPX1{C2!vRe&>zd~ z?Cl>YDk}btQNMyZfImFIrkp#};1Y~ipe2xtxZFd?;FS)poxGL$n2Ii_5wzrR9?;gg zWiEV{jx781NrQTNF)!VXvb!6abm*|pot+yYa06+~!Dn>fC{6uOf^Y`$R1;@SX80OY zATdVu>SbYs(sMHU711cuaZNPiHehR5_^O+eRD(`Yzw1l4unl_#;w`2YGn#LV`cMMRKl{@?U zbK?ySKNKUAlP`~>?0F2#72}Diu31ksUaVK1f0|=pRy)=Ec+Yefp0cSGe?I}fP@l6= zU!iY7vbU-AV33nuh5?$i9uHk-IR}9Kp6(2(6dVys zl2Mrmv*K~EzgNH0;-g{p{c}`(w%}La1Mjq54lb_s@c#V|pD&DW(6mDA7w@${kXl&Y zF;4s4BPkN20&>0D8DvmamUJODky`_WQ^z*2+el4s+-=gbDy!S$K0p_%Z4XTB85 zE@yE$5a_tQF~P;^r`vknq5~P52(F=`aj#a|7*s_|p>oa7JFA{&khss;llrUxUG9ev zX6a*ObrkqQh^J+8BN8xA7WGS*j<;{G4fOY0e~!Fb|Jr$j6IZMXx->9UT4nI_^8U6& zVDJ0@J)yp8C#QknMyAo&=Y4(7lIJ{V%cMP_!7SR0pt)(#IouYrwqcWJlJo8Z0YxZv zVg5iyvrP0KsBc_yLC_$3I2m$KSzqV2Jjn(o@P3gV7CV*rkQS+#EN_RmK_lq7vGl8G za~oCS-65b^Yu5;#JoI?yN~ug$-M-z!hYyDyPNn?{#?92AXm9#F{Eg=F7oB;%=h0S^ zvot(1Uc10QE*cl7ogqcTF7+cXLbfP{SC^#7lbxfWJrPyc@jLY%?76B!{uO0c;TaORz3l-73f<|FPix3lsqii-HyWG&)@j&|b3mZ?vZT5a*kviPJrZ`p zNKKN|?d)xnA@PbTRMwa9bDX{3Y_>EM>snXNOed8X)kt<=tvH;sDVh-1r6Zc|HSR~R zt`C`P7EKyzXnfmYV!J68jX}400RpGkRWXpq9Y6b{u}ZgciUM2I;%YltRu85;Bc#l5 z^J`5`;V{NRd|(UyaQQ|PqA*V}X=NVhrLMun7LEkF_p}Fn;zqIMp(YHT*Mm%844djkQRWzxf{0nIl@Y}zmdx&fia-A_!Hc1Mq-FiRb*UrorD5+u z5ubVO^?n~YSO67y>3Ex|?=4$J_|6ai)U>ZnXrsY;n*HA`;@hdVbC>Aad_>HIM-W2# zbZfYM^FmMHaHGnpVFok zdT3nYm#`#Qe7;Y1L;r0_OfasV=<$^!tRm77?Ctmiow!8cQlgKjrR zk%O+H&dhn~=~Xf`n(rr6x2@nKXkZz{L-N$ZyOO@tAl3L@~+T88TUR0Oa#- zQ@bIbVUx`qw>Xsn&cV{nd+T03`Zuh3|5H>SnbEzs8Ma1SJTCBGGAgMBB-*DkNFqii>O@K zqK45RQvwt+6uqG_g#_b~2Z#81nqik8gxU^zo5Wnee^ur8HJ%&$W?i+Nh?xuT47l|{ z3J+|f_vJ+Gx(#33l@E@av3#1I!TlOj6=XBF3sTh5T4 zo3!O}wW!N{uY-@Im$n+O_ipXz7yvg#KaD5{&?uA${mBlZa-BN~em>0LI-NLnDiFM- zI5zP{KExkAkM*g-DYKyt8k0PBzTX}9AASFkZ#mU7PQ2aAsQ;`Y-A6vgNYK#Y98=FG zwHbCIK+#OTCIlBFOk*QGPs`B5D*UzF7^=QbS}5Sn?LIL3;+9Ybau<|5hKWJPa65qe z=n1lvZUkUDW0i7-1dp(S7%#jpkQ) zxG3qK4v;p-FbLg)UG#&!d_vyT1(vh3%KL_5DX%)A@N`bXW`&MxoL}y%mt?AM7Kmw$H z^Wq@MxN8rgagU@u?!hWk2A56V6@M!A<6anv+O*T}xj8<3YO$5~p}+52gu6uw|AR1+ z7edvZ)v`+7y}pIJ1Soqi-M1XkjOeG`Wyj)njP)t32!R0lil;t5l%=wgV*$l=AmNnx z0qG3TR{kz_2%NpmRL6)mSQxrd;wULCa+ukD9QCMU&^T7~zMU8AY<>pnex_8ROUz*0 z+1>zAM23dl;09t!4@C39Hzx6qJy}+;ubNDxc|8E|viPBC6=e`k+XCHz)C%&r&1yF;P_0t>VHs|of@aC_f0f|2gTrj`jPk2QQ zP^#~hhhbE%8@F(%av+NibE&BguPO4%GW5=8dg?Bg^RZtNQrKsTisuL+yJIFSq!N3a zL1YO9(4^jX%~GQ##F=Y>+z`_1_!=BSiwWKYFebRu8ssE?30C4ka;1#c^?Tg?-l`Hi zJ>v2x)blM}&J_Vfk&$nO2+&f(vU4J@;*UlPGpIbyOqp!L(p|1*lIJPO=K)h=4M~0L< zLse2mvIi9hjS=Y6q}2*iPj;$@pBiKD!8Tt!kAZ~ob^zEC=H7Nj2<}{M1Hyhd1E5|z zs170LBLJ8@_$Bx|F`pip%Cv!H2GBK?!0uivO_x!@!QOYnaJqP}_u&{ag>!@=a_L4~ z%Hj1qFU!iEVuf$&=y=$lb-sxA1)L`pZeM*@@EmM1-_cnH$VWevS_nQ&WSj(-J3=sb zE7!VytWK_4HvQ<&pc>hZE3>{yu0JnrZjfV_k#AXZh$|LjX&zxKsR*NCC)4Qw}IxX38TUX5uvPS?=AaoZBiB z=@_1L$V&Gr;@>UNW4|b-w&CGe;$Zl&wq(ZeVok0HekPT8~N_VJ#E0yd-VQLzm zmJ|Pauf%&wdhybG%rOV1(mW~Osqr;{MG@v(k>H_(_$UxE53ME`zydUgzXm@ljMM1M zE{@rVyZaYr>eC1FpAYmE(2v!~ySA@&&2ksPx;I|*5HG3!&}KeNQ1!E@H54lak_a`3 zvKzgvJD6>lFP?nb@3HWTzeF$H-EQNzu$XJ8%ehXXYC=sXEs%x#0s+uKogxyT6&Lu2 z6_;pb0*o4vQ4Z)2OKc?7GQxfA_cOImFR<1g_7xH37`W^?gVkhznGb~>6O z1jC;Ljx40#52Y14LO6VldXbn4Etd`~AGd&^`N_68>Jn}9j@_&xf-nqO0z*VLuRq!& zZkoC^wWO|aJ1q4&@!$wz980EiBgZt=;i6p;YH60uoy*fi?)N!-4JZ{C7$Y@w83-MJ z3wR^2-%!Nv0zQ9<+CkbZa%I@NfY15cRQ&}e1pz*s=9l!4G8)iwvP#jVOQk1{cuCU% z+JVfE)v+w5b;+o9kGln2=!7Mq?DLvIfzIXG_4nNa0s46JvY!Ox6%&~XCL^Hf-Z-}I zLN9ROPU?c(T=`Rk*EZBenh>{(bw`c`{)jAAfKlY9R~t?z7Ms7urDZf#ekPT3*%uj)O z6xY9Grn?hmQ3LV5pZ&BGG*AF_=iEoz-v>yrYrTqzBJO3y4g1^Am}FpV)I4!gP(u9# z{x^`%jG%k?<9za1WhaPN)63QT3+9Ju+>L95C5DG$Ua`2(^8 zkRW7&7%9>pLwJFZ@~d9|d*Q_4O~=RZCGweR%(mmYPY*p{7}|~gP9o5Ru(lWcMvA8_ z=W5$YpG~oh#DnLK)1N{Ze+$@_yA@>pz->^E@!@|ge40TiB$#cDUW z1kSX3X{5xIOX+i(Yy>>u^49$r5U)mbBmUyJ+%XwabTL}DdNjkR;FE8Nmt zq3RbJxW`xroQXb;w6JTp!HPfP_fC<7ZOU9nb%GbILRsMdA?VLE>~%U8cKGHW?+io^ zw&-7b*b`$)A2GP8FWoCc)Lj^n(?R;h|o@7lW(2OL{n!rt#(aWd0)22 z!ykQ#yKzYaE6ZX0?#_z2KAwzBC3xE&mZ3+q2E*d zy+Y$swCwAcctHI8!XiPDyAh8ymkxYNmY~6RJuCj@r3^M7yDAD(-pTO z9=_EmRCpo-Y;>1Re}RvqL@mk7bK2H=EVswVQpAvoSR@Frvkdbi{3T)r!!KnKL=7&h z`@5vkuZ&r-xpMag_wv=(vuyd$$U z$Wl9uEG3-&cOY2#vub3L>4ZSK&M_{%<$~OND8=-5y7c0WN)&3H_OV5S&x+0bMy7tO z_j94y==|bgN^C}FM?R=YRHWm)DmV5Gsn&|qifYm zCn@kGRn=qd)fP8~$LvO3Ngs}{P%1AOwutpUVKuVY0uh@$fWrd*!aBJP^63A;eUNDN zzgJ{B$xZKpxG!&)f!z0`5(gQjwRlGMaAv6j zcaedJ%qeeWU7ifD$JJ*T=EbmWF;rw5A^Cs9Ww_xD1qN6Cw?%ofGfz9_+sA^Nhh=&d zv5wW7D+nCuvkIxNn(uwgB3ST{`&zbe$K%Z-c|6a4&jED+Y-I^VJXaJ~a>q!sHGCtVZ0 z)P3J={z2)Z1hT?clx1P}BuqaDP+*DWlui*dbw4qytUoxXi4v1|WMZGMWw0=4_o?c; zw~cc(4@~lqlBOvxx7K|LdRxTbzYR?itIFV}KK}Y=uvZ)WxsAgY5*PjbpMnR9Y#)T#%nvX4CRKcWq%ly|jUUs1X!6OHfji><44RBjI zXJw`Y)J^(-7cP6X4OGvYOhTVb0W#jX-4?j*;*e_Q%8$XiW>-5m`>KTdHG|0IAad;3 zbqp|TjFCtnk(ZLT!{`J7C42fGra>1g+I!jz%N+9NFd(Lc!d{6gtrQJNXUzi_AH?hb zQD=>%FGcZ_W3MPsk3ps#6lwsc=0o;EER<|Jq;1K!a1H;Hh z&aIsT>^It72)y=h&N&D>JhMof&~lVA0*7G^u=B$Hj(I}a5NOc{S)RXfdTJ$ync;vQ z6n(u00zw%5q4WAoao`3Z9>7z{{@zsn1uIcLj8s^Df_nxOK=P*d)H#vJ#s^t{2_NIS z5xJM~qM)EQDJf}v#I7W-qC#tUcsQztYV+4|1xCH601pq(^0r3-Kr`r4`h{oTV)i$E z4_v)hlg70`9)#-5x9kMt-tS*xT=v$7*ed9O&;Co}?r|J{gwwoLB?!i?eX+O}-n1{X zU*09w2g)>36h2xOlK&I|t2nDUw{;Q>V+=14g9xqI9C@q=t5pD82wBfR(XS46#-m&? zVs&f<45;+1l7@EwbJa7M80% z<>Znr#Ra%7!0vs*k7h+0V3?rj{wXji1Q}!VJ#1653%a@tSI1B+`xtnhywlh zZnb55@*It|oRn!nvp)La>w4iGG19Xlu+nf0zn^SyCjRIJEY50i&4D9r@B^Q4z$bOX zdZmNiepl_=x9e*Go99_v$_YICP@J^M;zlqW;;soZ2PJmCI)5zy0S7G*#Ea6V${vC$%e9WWSZ02}lVPF-XT5b(St zx*^XX41)eHsSt2XaVMnn{UlEKZ@XBq8+PB#tZ;t4v7dJEwl?UT#$ulN$U95_nWEt- z9#Pj&{Q}F+{cyn6N-qblEC8k=X7rUA94ozC<5)`*;2u(|`}^F}7L^Oh1~%Hjr=W?|;jdg@iQk(|oY zKX|5$-7@L8Qp;)T&jNb2ZgHLcoP&|YPW5T;3=tRp4vm`u)bUNnb!N? z$T-C}^*>%grWA7ASjW03!{iZd)&kbPMKm*3=5Fw4$?)bqK!v)_R#kKxTD zISf@b{DHMQUlz&a4Il=2ra4(9Aa1uN-`vFaVC(j|7g{D~6K>S%Bl#!=aCSIONhKE2 zD3UFBAs`1iQ1-Y-dU$XdVLE=@=E~7OZLO7-fSZ$TxNgX$mZWk%m4!*Nd{xl!iTTNMAZQ zw+om)q`tjE9utixjXZIv8bB~$j;{vww-yJJe`J~PPJ(3uwW)6YMQl5Q&U0!_Xtp~E z^(pA)bpwaG^Ft>Zeg^W)*_rI<8@iC6^;cr*c6QF08C72}uoHG3B^Xhw)hrJUuu2Jv zClOmIFxk5gXal-p8#EesEZc)wpOujZC;Hi$VTUqhak}fdt^0YaNg3(JmNxBg(rjB^ z4Aa_QN8uKdsj*lzT+`%0NF1H+k0FouAJS}RTYne3 z)Lv>r{4THteu>AAy3G%1VJmasa;EjT5---)UTUZY6T+Jl{AQarpdKoFpqYviH;UJO zY@gse7@#ff%g78?a6g;e^QD{{OD3r``xrPWEpP6Qs>Za zJU{W5i%ngXhm{fSPV@NA*QYJ*wAM46CcBLBR`uRrO;i0G_PKoBfUnZgQW{x@7-~xt zXBEH3iDp@ZU(m~HEv}wPl+O`NmBoi{U;?}saes4QGS+)tim>81@r{GFl->Wq6$-!< zyQzqq=z-kR470Na%miH8v@yQ;%j?OLCzLA(Id0prdB_b>i;~G*&~1fPjLq9{k-#af zudS=ewFv7D?R}#7-ddk=n)6wP^IrWvBLQsmPhXcpK=}#0JjF&QGi++zR*xLRe5lE; z*@DKpb(cz-7;f>dVw4-NzrqqiQ89Gs5)(S|;!RUO*s$fn$B}(Qkne!#TrT^&?&FU= zzeJ9Xj>e>6*6j>T|rJFX&`>h?e?yhMMx^4_?pY~Opj&m8&z15j#na3tYjJdr5h-yOa zD_K8&x$SJD8T=~`I!hZsFRDR!9_aV&x)?-f?-&;QCuK-~zSgx&s|FU6y5I7p=5CIR zr-^=1S>U3#d24H8_S0G4w~vE-WrS{^>7Ode+yJyJ-`B{pv#h8KO53}^&c3o&VKrX2 zHIq~(6X3lRZ(#q6eiks*ByOJEX~ROKqXj^C0!_1a6bN_B#gUKN#CLxA?3j1?pcCei z36VA6m)3O#!{uFy#QukfWT0>Mgoi;V^)3swf zXL=)uxg#;f!Fuw8>+{S@(v9(h8$ydly(6h{aNn<>nIgD5YcFAc`Nw`|r9(-FeZzH3 z>gZ1(yLubuD@d`use;@V-*1%IW7-l@E@j_nv6$Aq;q7_Sa)hu}Euv=G*t(-1U7wt| zJ}SA#IY*K~R#$0PZNE38`CypSqGKeBMBG#N8k9fWTibHD?q3D!nTlQF95fbX%k9Rl zTs0Hs?YiuLbPyjg0W*KiQuM4+fx};Oz^#SvB;OKK$rq68VV(qSJJ^*zuX}ekd*`IHxC*BOm){Tw71?ypVH-My99!;xWZ&6Jya@2)ImPmcVCv+SmBi0`C_@ z#$IHp%s(U{09Hxh4F4NO(=K*YTzA95AH4uf zP76HzfFFMG7845-ApVey@SyUFiUy!qY|LdSu<6MOyw~#Spg&T{yOkHR;k4Pe%s)M2 z3}!(~oe8@9C&Kml?)-;9I+QieY}%l#$j9jQ85-R?ibbjxQswNj&pSWa9}%|dZwJE} zPVZAOpWLY<-az^EDGLO8KXhS1!UfE`R*H*@2SJyyyxrYy9%Hll`+(lF{#%91a6@su zfxF$vqDa+y>Qrcjn|{4e;v%niqub&QB0GM>u&Rp>78W?F9gNfMmDM|Sv??w@i{p>j zrDG3Lm+z{xc-cf8v(kVA2;xwgfV6usCkjA-GTs@wa29Pyv^lQ~!%pK`+Hvbuo+kIM z8g>AK>OomLM2$WWA4PeocBvmLgF;n_N6SO>Ev>Q5*n_6Rqjw#y4Z?PQXOul^LI@y^4n07~Qq;yRyo4 zCpvqUEajX#<(nxb)U~mjdK*UPA6G{kf9i1oydAKtqQq5z)?YW6U2SV!bjBz#$7+^& zi5bo8H+l0oqW=iMi#wc?b)+-^51{XC2E`oo9JgAfK=rFVXlDTm=$AkN{czlhc5Q|I zuh`B@ZwD2xn-~^d^pwCd)X4oZ)?=LVBzw~)f#p}4B!{`Aa zYglvkIBnPs74@bC-_8O4r_&SMCy>>$S9=?-#00onXg~BZh?mZ#_V}0S{OA=NvD?Y% z`~^*Y!`qzcmy^gHgCsmc;Gqg~1?cw062c*q8BH}q&c)*1RMGt$2F?OFm-b57zE+*? zTi5fT2;2l601>K+_%mw;iwf!!B|nch)V(h*NgfG#Ay1gI?0-c!sVNafy-3U-n<4 z#`+llXF3t*J_vSGs_c3f`D!`PRK7)65V6ueW=ycII#^CQ5UQ5eFyut|X`IY6A~d6vg;oC1cj_YU8`#2GW8 zjov5U0$js8*9Ok^AF;&xlzKq`-Jt;hys3C%b%057I*ivFftx$~xGG1@j1{P(KuhR+ za5qT?WKLf6QXktLiF817fU4sHF*8h#pi&-GYV{MGBt~{7MpXSFy};pIWaYa?43uAP9Ekc0$@`2TzI5EvR6 z1=ZewUWgfA-Dl~~pFeNGVs$#j>yVIQSe5>i@Z196{|?NGZB{=!DGRzX70q%W6k#Us z+|*Gh)OJ$C79F@NiYH^#*khhmIaNdt^fC0lhn4&fDbH;!kSk9!yiEz<(7nTu5OA*d zKnHGZ8ylN#$w$(ujFI+cJO8tl3>zmQNDXGJdo_cA5EKf+v1sMKx5|BdLxwSG_J?J0 zPmX03YEvN^li%b@jZAU-Q~{y{iAJbXO6=vw#!v>d4HTz@8C-*k!^_*l{&rWvVv>KB z2iiMK$y1h$7BrzofZ)7RDHs$Gy&wbs zhfx1}Li8_iB|v!@nSs#VxsAJY*SZO}rP zi(VpufCq9T_Uud7?CkkMeV*Z`p9j;gp3>Y`q<=Z}cIOhH!=+pev3v!V#0dW%B$hsF z^oeuM{U6u0&t=p1e;BFD;XSB-DA}T60bpPD*FWvWI|m&G&NYZ@z8_zV&42PkUwc$w zwDwfyEV(?W55iH);~6;yf;~KY=g++Z`0xM7_ri0or;X)AXHeBtgY=1pUpTc5Q@8Ga%kXu(U>r>dN?}ctidJzR=Li zw!_u7Kz$|$AgukULZ5^3J8L^ ztgIi@Po#qqs_i@0ivLT1h+CBhVK_;na#Y(uca3`H&U$XuUhV~p@v8@3gVjR4`q{gw z79P*4>OwJyB)7zhAxk6dU85m%#rx=?@>AbkH1~u^*$pQcU`JhLG?sc*W2A3}IYY## z&9isvxxw;-a@jp;P>IYDb056F9Dt|)bKwcES3>ZUV`{_OKw;|Jxh?uUB~Mo=Z>y zEfRAgJosn~Nmae5y{8hjA*BSP>rhJ6BeHjoMp z&f8Cr-+0jJ&wWW7WQab*|C03Yt?Bik%wTGdA(AxNUwiWM|FQShQB`+a|ES`Y5G7Sa z1xYCh0g;eUM35GwMUWKOgecwEpoDa*l+qy^X%Xp?j!me9)COtkJHNzp&U4Q1@qNd* zcieIRxPLf?Y&I+AoNKN*KQormCHZ|4uc?5>x4+r2rz6p%R!E`wM{e)0^O8HiAYiyQ ztSE;Lv-iQt%6V!$qWVVip!VINZOoJO5CxX}Hc5~DZ>N!?4YS#@mE3l`V$b*eLII@5 z(t4GJ2C6{>9zOfyB%Gb~vvY;F{Vr~U!;jpA2E00$BY*v-)$^^aUrHH$zIOU|3Fyd5ARS{uxqyz`|AX>CvusJ-1L;hglJ#OO_55|!!5 zSRj{$Zt3Nhr%VZIO3s#O&f1CQl(tQ2S%zk$=XL(zvQ4l{X1@%YmbYy}=zXFV@T;YWpz)M3M>IF8T4@=pbU}^qF9>fr0^yn$zX%P|j6T z&Pd(27sLEo5<)h|Q!OS>UhufZo}R@?kD)0&!JAQNPt#v=T@AY=x3R{-^7EQPxUfRo zbbZ&f6lmm^TfKue32M3XYsRN(@DF=A!p?`7Wr{VBBgPA6)jv@{ggzMCF<`RM5;D;> zBkMtI3H_hgf<2ndcN&IST{(F%1Hy zb@*=Anc%ol>;BPV!1M~v8a%!xnlsR)J)2UJqU9PV$0b*DIq0e3bp-0x$wmA{*X-u2*z3Tl4H5}WXGG&s4-lnP=v0-`fKZj3zke~?+ATUzdHHaykt zY-U7-_r;!y$h}JT+ouT%1;=7J{VPHV694!r3c+q8%ElbRk9qb3Lp@>gV9g?1jJty>s<^SbPY-dyOBF)Aa+hPMB!abMxr)%$T=^GN)U_Mi$ zUOwBeAeA4$O87@(^RGh0|4$p(|8mffybU8JujN4xJr4*3sNK97{B;(KTi~fBF`H>fk+e0d%j!D&u}(31x+ZSdwwUp zgW}q?3iaB7Jgo3OK`+KKDoG(K2`NgxgX=!_x71P0!+#EW%Rdh6E~~-D?LUB@aK&Nl z03`P?!)XnE%^J#s1o<8vc`aSJ-C;{X2SjxXV_2hYjM^c(w+N6To0a2iWe1=HydE3X#h0A=;AmT;Z zZ{^OP;dh2~H4^(DNJ~FTy6O>@V>*p@9jP0maE!!lHz6W#!#98ol%tAB6_5~8uCklwOqUB2@`-F+j+aI< zxLLrH#|iGIAn{^?`;Ud_QlmYL?-2hCYM^K+xel=)Ndl*lQk&hB%zz%4Fd}B_bqfH? zHd&Mi{1v^A=&8gjAXE@4)})AtNgAD>n)v=kdRW5L)aenDhK`VaQ6KA}fAf}8r>B0i zPcom(?k7I2c#!A&4_VO({{9tpZ+eo(euv-T9V0&Tu2eKP4d_!(7i2ZW3 z5q*dgO>4w%N>XK(7Fr*Tb5F6T-YhXWdStQ)9ZvBK$D=Gb%)Z~D(!S`V{d!caqrn?{ ze$-*URLy$#LixcMw>W(K(*ivp9?Fbo$x*#~-AgR&QEGbsmS>Sl1I)UR1ldNwlf&Eb zE3&(B*BFa&d~{1>b5ZU9l`W1CaoHY%Lx1!61O&wh^UGbeJ`UFHRQ;qj#H|6ueJ6$Jy^LFCHntYa1bk z{C;11z1bIgZX3a!K22m};BFRC2}alhFlI)rGzBd@o{z}kBBZ|As6`waJ=mN@d{$W> zcRSWfyEvtj0xMN6^|ntE+N$~(5HW7I4e9S4KUwzGL(e#bv+WeLxZSNGAa!-E(>fMq_r~^#d_UlMcft-GlfM2szCgW=ppSE~!)m+z$=BktGC8N7^wo;ku)JSU z{!E%;xq0nUx7&-Q`VE6MN&>xDPk0j~v z@d!FY%s%67HMAi)$a+S1zoiL4;~vlCyH^MSrJdw2*>c2XnPzTI91y)hac*_WD^K8N z%2s%_E3Zvs`Ta=orm0eB$}-IRru7|>CZs-4VEs#8r=9N%6SQ9ZO;MeZ9ItgMiS%o{ z$P~A8Y+J#^q4>NJa_kKj=I!oPL9vDxY+MKnMubkg0H4s;0n(gm$|h&h8I-fw3OUxHnWa4$(%U|H#JRMS5)p z<@8r;LPMl|KOX#*jB%JKx^oWlqOT9m^^T-i47|H%A{TF;?~ktsH;m(UfzoBQ7XojqUjU$AO839ehOC6q-P&(% z@O7=pHo1L&mO|U)&ycdru#=oSi|Ql8F0r1p=raG+PwaM}?j)Z^)K=L}jf1Ola@?g^ zh4c>^%h^{4-!@h+aPwVTt&3PE*zR2^P4pl-+r(&4zp(~mo|iFR(2VZfZQ4Rowo0ks z{va{4AT3SGdF^u<>)tF8l=mmGjt*_U-#YI|V+_18WZj)nN@}wk_xsPZ0^a4lnC+C%z z4Xt;KVX9s^oLn2Xm;a*&MyfZUc1Q{Y*QT>=Y8E%XgEwPKE7$kyob7UJrM;31*HE6 z<8f%<{u+4_gWL5xF?s#r6Fd?^LP9%G*mg$mbJQg$vePoz`dq8(_3iV z+!5&y_w0wc1D#Ws!^+l;Gxby+`!?3sw*|AQevbK}8A)j~r0sw-qQbuQnI%OkKyI%T zj4GWk$}i+PnEVCP=w2VnsoQaKYrUv!t>|`T{=G_6l7QEeYVTb9Rt7&@3J)1Ju%~3U>Xh*PQTbuK8`0S;XOJ%AH-Zxgcf(-!2^|&DXM}98vM5H^L?14= zq~emaj}N2!B=*}V7ZhXqi>=BmrOB@~L$;4AU)~h=`6=qKrRMU71d~1-88S9X?`ZMH zFMo2+sdTq}2fYbqG9fvr!Qo8LvTB!TNK8!3$NkWZ`t8(>(nYUCl@0-G4RTU(CO?NK zooKx-(M&rR^{fqtYv1zRp|OjQYz<9z|C=EZ_t)6E!ccwIj--pRox_=ZX`v2F=8N&h z+SZx6)^6mNwi|&|3J#qYX2!e}kt2pklUd6^ zn0hMu&6b?Xp!3|%^u^<Vj{tYDmQ2E4G|OU1GzCZ~ivyclsHVQ6amGkJDq~zFqvR zTQUABw!Xd?QW(SnEqw{sn#bFc?QnTrt0opbpFbb(*U)pzn=W0m8eHK&DJJRVIfOz- z=<4W9u6Y=Di5hd)8*cGhdz|mKQ|h_$HTGCf(Ju?tjV8UZF}=?Y^SfCPSv>W=A9g!e ze(U2jPmg>f7)wh!xZlr&fB#zc%EsDqD#X2^o7UV$cIJJZ)&bY~#{RCtjgj{o30=>~ z8BY%#3+uKLN$)Rn)O~r!#jszEai;6T+dC6?GddRbJFJL-~?SG#D7 zEvZAN9*H%! zPTt<$ukAAQJT~m&UT67Z&**%z3!%Aa6>U|76UaOqxm} zQT6g~@8i>sO3jMC)Y=VS-s1-VaaX-l6kb?#ng!>_u;i6 zB=~~kn*7oxzSnMLVCzcFw4%MGriyg~-`Zm5kFpjQkY!rKKIBDO7&nB3ed-yW8G-{bAnM zRSRa0RC$7CYre?5m)-Wf6%eo63EfEWgZtwzpT#n2qrm|{(o97!cs46j*2KDM4cyV1^U;R|=B9B{XI}AS&I^gvTg}wn#S474L%$b=emzk2TixonwJXJ9e`=6YR(f&9UHsPTgUNrIfVE^w= z44kp{MH6Y%X+!DMX-nuSh|X(Nj(zRv?*BoSO=F19HjVE!ma*tMIsQl({>^r_5p|-c za^fb|F+GP0AlO5$ig8=B@1Yb&9-De*EVzG+KMwf?bZe4)VZ_8+BugGSRhoX@-)inT&U7iR?Z+oO8DS1H%Xc@o&ik*J*zp;P z2D8o2BW#B-h*;;7Zx=(bpD7ZrW&DVQL+Cf&~Q){33f7mkLSU3r-HJE%rKWy*m z8|(frOIytY8`2tTgDYho1eEmV%CEigIX-+onik!SI<2`_N?VD^H~T*=Pv*JIaJboQ?F-gh%I^GAvt)cgg zl76?Ewr_)2O^}{Cm+gmJ-j>qn2UqriZ!fWL zKNTJd%k}GRXNbOt`LVnK(sE25u{602`|C^HR{Y*L3UABg#kXo>Qx-`H<x4o21b z0Ws!bLAh7lH)Ye)&e<;?b@9gCRJ%>U@|BIi!ku-nH~N(oDR8P0j% zm10rN& zlY)%gG;Uf0g7cSi9Liq^sjM$r*LYu9-qN{}g?ml+;PNg{G=L`=zu$I5=!kkG{wOl4J&Ei7cA;wmH;0Ecif1*WLM6 z-u(D=V1&>ZFydjxzIkZ{PeeS7#m8ajwpt@G#jKc~r@1ZUblrZ6oIOMUGkNaAD};e3 zRoD(rGIgtap7v%V#7HWmLdn?nd*ft6f*Orr=qAsg??=n+@lPvC$-F|D|Akca4>eOD>gkMq$AtEU#%R91j;zm)6?hR!r{X+M_-oq zdUp^DY1*;H>vQ#UF*B~!UAAQCwYvImT7<5@zdxN@pKq>rC|lEw;5Sn_E*gD-zT1BE z8ut!`$ZWVIvT%J|wxUEBMhz8#NBi&&p>7_;di<_9GYr|Gwv*}k?A^yy>3D9_nU^oY zl{NxJVmam=DYH?FzX;1QPs0z7$hWnjWUMd>TuD$qN4Xz$1(C57+pH63V6QRXDWJDhe3%2Ur-_pY6N7DmuOQqw z2A{A8Ux;|9uM>178@z795Fp&Ux^e^8qjcT&Pvo+24KHsGfGCLMGj-crNh|H_?k31x zs&c0hiMOS~p-NtI3A&pw(i?UH-`N|U`dDhNatz-^XD1ef1h4e51vH{ND^*5h?uu5B z5FzFQ+tK=~`@EE4?58QG&s9n9_qH_s2n*~R8v*WN?#p>w{kz%C#A!HZL(0ZWcMrj4i%5WK1ugX= zu&AG*uqfQv^KIGjJOrPV1s9z(u571xpDW~UCs}m!m{M*}ebgulJ0SSPDYz74va-Uh z7p%mh6zdp4#Z_Z`(OpSB^tfVQ=yAd?njp_rmHs`Qz=mVd`q+q5CB-1|_Ey({RDQ8L zV*U=!?UG#2oh;q9uWYA$iPyE&s_qeC_~x$uFdD+xvh_S*oh%7fyC~zPcCQm>_Dte5 zaCt~`(Q!ILAFI_5L;vI22ZPrVl2dh@=jWKX8&4Nh8OrwhTLo#!2{7w03Csjh(dw|3 zf9YjFVa*O5dsESv$HA0M-!{l7bE3%dfk%ujh@_}% z0QamG<`jYZ1ZDj`f#?o=FVDCK>e%1O!<@ ztfo|8Ryb`lz_u72knj9>mK~kQ4xgy8>NK@5yL8Ei6cMPvJ7 zjt{Vhv~tY8`AtVM;&QV2!+(}kABt%-hYh8>5%oxff-GxYd1-bnOBDZ6ejRdxf++uc zhK3gHt*nOIOZs#2J(5ooH@y;%r?=BGbgNI&V0sE89ctUZ6b|Q5EYk!VinEboDYQuO z-TRDRBZ$F3D^Z)_fu&5!)0jX+gGDCBCQ& zK@4+n)_q|R1v#~U0vGlll!RhTe6m*OFbjSePwPiM4E7_RK)197X{MjPOE|-A?rXY1 zQ6r8shB=>BvCKmwpRLGiRN#onu|}E!J8)@_{-_Z~f`t^P(t{s6koHmQsNcUjaWOP0 z`p6P@o8WVmkv4yZA4$8dBIWbb&|x?dr|V7J^WwqZHSF$=teB9 z=F!H)6T;owc!7)xSY#S<_77*olGXpve$KU!+Q24fHqNX|Y%j6uGPOyC!?iw<_&sIW z-Gz4~q=_&Gyd6X>pQ1S;xuPOlj|B5%)EkC&jkHMD8`qXReMNJzD<-r$wE6l)!fLn$ zUIGbDo*?td%uv^`WQ?8pJ?w`l9J;JP3D zM2=6W*DpzB;gU1r43}j#Fl)olRT;uG<>zZzH0nh!sO9MQ=`r68vK+}ZQk{#Gm(i7b zcrL#%9cv&@Lht$M*}n3nX9qLiBBGyG`X@P37>SLIeIaU_EKlysB6gx+XUO8GDbzbB6(I?zj!N|5d z&qInwc=bArB->%c9RXD38&43I&Wag$!e@@$MI!%wQ&{j4lw;05Hi!UAlO1-a9P+U8 zH*$#`4*Mg;(rQnmu#rc7j2S#7-oeHs|bpGPH#XYbe+(Zz$l# zQ4`X9;g86W&7Y++vf*-8`t>)OXYmLhADnW;j^p_B;5$^@Q$zNe2z&iM8@dIzlBho`MDR*wK#(Ggv4v(o>L%|T-#IbVTrshAx``U@#J`w9xrH?I5uxf@eGQp!-%e#PeGi&zZ=*8MLo6GnM%$tmJ8lj zKhgUsYh@MHo)OM`pvU3yY4i%bkP^+?_qhoqSw#E8qU5J7eXQo<)wuV*O|?riddwzE z&^7If`+U=u&3Xhw_tFsiodzC6>0}=IpXD7*c)A~RB@}(~fsz|8%-{Nm--vI@Kvm zULj2mquA%5?6;9{sXn%|kr0!vE1054H>O{dYnFWL_5x|ulluu{n}ao}TaEoNiB5lB zg?u@(7l4ia!FwLDjQ}`s|G1xoI$rvmO$*wIXT=fM(fYMO$A>s)A{;|rZm)e(k(Gjw zw|jcVI`FA=@ilj}Ym%*PXAQ@hjfO>Jo|eZI{9b^4h;Z-!pJ|puCb(jh*idv|I%j0H z+FuT*OPn(nQUHPrfXga3*{!U8ZfhKtZeD{rj%|pXDa2(U07vTz^0!fD5>9^_QLdAq z7yr#&{mR>IWnmFyky)btSSf8(5VFQ@J!p}#g&NFC^T8WfG&C=GU}u-u-wCRcSzKJt zq%krC(-@+0o2@NbNy#Oal8`Ro^6PC!!AL2m)8rhV<1d!DfW_({qOI~(5g4!;-IT4^e}V=^rrRKY&Li4LL&D|(JwBjOJKh% zHakL5_zHxQ+XQ$#puLxxM(s$LUM%M2N?Fn9*5=&9Z8%^b-o(KV#F)k{9-fCH?(5_q zfB0}Dyn9y@S5AE){gdA29F>sAX7TXI2(zT=yj*tlCh}HA!&L=Kt%VhuS6$aISRXB>-rPFVDk+Abm#5)!NGtyp>_F}{qHo&?cq*EGW%#m zigC;N1J0?fTYAPWUJt&i!xir~?!H_!$h<{!$<6n9b8v8Q4N?yE{8THFlZ&8Bm#DsS zb&I*LJ607LT%z*n@f_7H?#oV38Z!ylXcC!W+CnPKpUyNC|Nh}?yfoEQTf_xbZ4<+~ z3+C!y&Jm7r>OYZ#3%j;Cc;%vUgWib<@zKGn=f&klY1Bqd>(^hbEVVhPOxH%S=mb&T ztO;z|P??zP=`BqU@gmP+BfFZ_Ke!gUK3_Q>6!$(l`q*5nblJib--ue4Wl-QKAuAQ# zE`+xOHpocS>the23K$#LIKH@6Vax!)DzTh+X41U`QJ}M1+Br^7i&wh+Blt{ZRaJvr zA@?ziO*QG+%Ey@H0T*tkpPlgTfg0PnbMiFaT_BPS`eGRs>#3hdO~+ozab0(hZD{U5 zo^2T(^ycxnb8#Vpw_*l)`{h+s)OZh_XzT9;qwQIP|pePc4Oby@-R ziS;{fxrgzw?B{%FIiDFuiFWabm>mfmi1MS!E-KO?IU^SB8anujS?<-FCFLm7Sf^{F z&2ilDhMXKNZ$)9(Z5M?Gy6;G^s}ElEl2lj$><|B7gWk~+;8^Xq-u1*=6U*G;)s02D zs$0uH;1zMjff7qGQ?U)DJ-07U=7fX6ncQNFg|YaNoZ$h#Mf&C!3*HmYmHIRD1(?x6euyyY4CmByof6(Pmc1>DszTTLVYIL8si|f_KO!1F#MDIRL^}FB$%IKU5lTsj3}%7UzVXlN2T&sSn_=;!eOvRy&udrxq@5Bzh3?3@3C$; zXMG_&j(DD!p?Wic7*mazpK`;3BRYvVqN&@Ez;Wa(9G_{x!chC&gUF%*@aJf)#2|_^9qIyN>q6eKChXzkkuhsLb>`Qrw zyV2amwRLf2>~%iKDo#c>7Jc?1IQ|e~px>c^XD6^$J4~?I$YieZ< zZXZT_ubh|HZ}u?J%bbcryc z5=Mk56;wL`mMv(W!i(_GJ5tPs6jS$7S6E9061a)g&Z5}S=48J>>0@=2(xn-@NieP` zZ22mm%L42^UPIOXXc}-aYqP=6Qx$B?WZMPFUGd2RDnBi`a;Qr>E1e8$05&l3Q4;!Z z0PSKA((00D0St(d_)dm*62bx&%1oipcDdsR1Jh(nT3|N6YcxFvcM0$U^dPM@1(p$o&E^z6B~AAVFU1=NNl9vjg@s1rt%-pT zj8q8^6Tz5DF~ZE5Wt)Y4_o`_mRoCWN$}!w&hfiLCZIc~;%)ECRSzz_CJl71#ydhmB zP?yg0ljpv20S!F70U*80WG$>1+(vcg#!EZl2fEkVK-)aWXFowm?%mToiAUId99XPy zjR3_9e_}fPoeA&FF;Lf*W|}8Wd~K;SsD(@! zB2wwHkxsj$m&gM?n$MCo!)g2RBMXvbvH+*EjCw&rXaplQ)l^(ZT|wB^+nU9*$6_{M zF$Iq-1UTYvDlB>LgMHmPKFWUd1*mDrYQV2Y0_KE|5F6-2;+;FYJO2jYGnVjf~JT-^B9CHQdM>#j#?7{JqMM+V7{4ud@&&$D}ki^I1 zSR4HPs8*nNa^iOs-p*NSA@ceJ2j>9ye&Rjd6$e5p>Wwqc2zmef$isN%gf#S%#hNpx zU#%?jU&r-Ib^bhXNj58;r0kwfK`>gF|NA3=+p4%P%d()Qp*h@M7>Dp9n7#J#(t0Rw zP%tD-u@Sq5$0t1?qra=_LtNw&#U9OD-&$%Wp3rxzoA%!-x<+woiHSu%SgnRC$uF*G zzMX9-jLzlCid?{K>Ifm;cVr|z1$4WXAOyD7EMoUPBs}5o_u%W95V&%Adre(Au$zk87&>iYL zdk)-|eyn%|;~p*K`ZscKegi>WBHP~ z*+f6*Jhr)Je90=X*frvU3r0Tbl|{!(Ly%BOpa}kP1@anDt|G)tk#uDL=hN(yfR8nM zdP|qldSmd^NMV4O5~MCzj$9HyPk}xq$wI-Ppb$T*x$#wOC2UQjPJRw|gRA)RCqGy% z4QDR{Pc{hUmunv+=w86S?xY>E*h@~~25Bl$=C8^k!BFNnFCOm6{rR=#obd(Q4EOj) zvjdjixIo^O4fC5>F;=`o+Ggi7LOwtEDdY$30f3-@Ra5N8!ibpKF;59r7)tU6{_(xL zS`2Onmq)?^-M7m&vexxNjn-K>+MZJg@ofmo`RB7bYQ zeo^7{$MyNSgROQyJkhrti>9bgzfK!{)^2?+=B{89qvv1ufem7Y;rV9}qTp=P(21$; zKro)3nXn$(S^EoCLGPKPUd1!h3bR(zvYxqMTRrbzw-7Z$a|v_XZ@IJ1J3!RLTi@ko zt*cwx$MjpW0!R94%L=ABozN?G74wTR-5gHDGqkQ{+9!n_i*dUTavf-V@QdvlK1caNZ?$nlhrCuwP8PRHrih8^T1PSn43*XOaK0Ta$5$P)DW6cK8M}<%3avJi^0p-0ri{eM<)_<;T8w;tA-t zrCMvlp7WdnG86LL;d=VL>ZK>;A{Yz55A{{8W_2dbCJf#V9C2ym< zQ|G%5`7=;^e^)}G;aFmSygiRc2{S0kTs?rg0tc9;E+>n1&&~n!0DIu-{b!>r%RYVf zVF_+%d!^j8TBVxU@)gXfJI2N}u~G6_xRy$uavryI0w(JvT+Zg~+4m(DEgw5Y8;h94 zv#owPMx4I1oEF@CdgJKyy%<5D!4R;sI?x6RB7hJXzsFuk=)-@!TKLZIDx%-#Ko0lY z3`Qg~TU$M@nTTmEbxGIkf7-8EbWK*^aAogu?f7P#Om}P~%wAp@P)YXEKU5BhrEzw3 zoeq{32qo3yqhTSbsd}7Gx`mgJwwg6t6Pc*>LKbpwPQXgq2AMn(%Z&aZawkUe3~2QI`qE!E8DE!Q@l!X#0jr|+S0C z)|Q&ocsl_m8CCIH`3}o#r+|!OkZk^Z`gTD~ROho@HhVA{3MQbG8>e z3w-1M_cnqw00c1ZRYT;3`YyX-sOW6%=wOCM--~v%_|kND_w$`zgGP=c^Ko0nnQ}sQ z6T!t$8Dd*ae{1J1+s8%b`O#7pQ0=DYk94*8<@8miy_31sxo2t<2 zuAd;$4RcrArhhyMd2!Dy&ma2_M=KqUM;<$sZwH)$|H1S6mk0R?v5yhy76h5LXO|Y= zJxYX#z1+=_VB?0u9?IrSV)(lU`3~~XFzO=)+5Zcd@&eVEAidJ&dcLju-0;Gw0-MWR zMYAqBIUji3P7#=b2l~22O2q50v@AZisweg%bGeY+gQ|@qbOZ+(_mVMwSCQ-n%7Z?s zgKu}j&DH?8wGp9fy&JLl`Y1}~=9xf4wM0rxZX0Y30J_DaV_{DsjdL95zr ztOsfg>#JqQ;~?Z_5KoC`283;Ewb_GI`N6~MEcU$36{nAtQ&=;E#J-F11bC8ojd>PK z*>{xYEZ?SGDdn*nYp98fNmi^~cUh7FL!Oa9)De;)_A^L6y7gKw662xgvzg6RAxv3S zkmNOAtG~v~*loWg#{@~24bfLVc>x6v@E7hWNJKAa2VZYwAi{JACPzKi7l}DsO&+eP z&(xg}@ML;J<&yCavD}F>nQX(92#e|C_0gCu z`jN*?V$V?6(3;a%KY=NUF%%Zwb&VxzV6T$5=|bv3h~A63b8RQVT&C0UYS&+r`RUHa zS%XPlvqxd4k5FHB@NySYnRi?19TjG5ZwgH3cB4Bbmn<}JbZ10;P>`0jpD*u<%ro#> z?NL5s9ml~$ef24)3Q+(sIjF}kXlKGF8UGA z_pf_nIAsb_jwwrsa#BgQ356|&No^C~9# z2^Z>h)&y$S)kGR@>aZ^t(_?3}znOe8((|_LdUV+H6Dv$~<8<+^it!>Ox=W4D$6)Fp zutNQY_mLq7()?`r=g)eDi~UFa4oabqRr{X_gI<^)iktzqA3;Fv&7h1Hcz&G)njXtI zL=F*tQP&6SUhz%ZHSLLuvUdvS&HVB|e0a8^RCs3oe!r<}_P__T@i?}1sK`?+{awkO zbjlkbV79M={Y)Mn*8``{tH%Z1_b;9uS2Fe@D7!Sr-Yo_(kYXrTGqZ%JYUpTaXlx;z zl4uze7RI8tQm4@h?WzHD9Xo-($j@H`L6fi##iq@%3Y#L?E7S_h_bZNEG+JMtc(5S| zZpOCbxJr1J3LSUJNu?=9B-ua9gd;}SE+u@6qQ+mw+S;1;nZQODDo*X;iNXHd zh=&5ZPytz*r+qobscRB~WI+zc3FN3sdKyK-l9b|TCq*y_%(T)Lx5+fht=!w&`^qbd z+C0j^Fmfy0;bxSBZsh)umB=$FvT)5$>pB9XrgiIW>n|Y5fqCU;a-2Imm7Z&MLyU;V zXk!#hn4bH}mxqaFE!%DmjcjcHt>w^57+0pN(<0d#bH@inyYC}8h4veVzwy_96k8{3M+)Y+bKh$Z{O*eN7%rLmkR#H_KORhnUX<$zkRa1nA=*oCoB+K zlj%PG%**p6T(q14iz8AMCk};|ofC0hco*)W`!OqvXC;Dn%k}$Xs$q!egf>I_idvC3 zjm;q|thDpizOF0vdiD*A?*Q+9b_-sCoz+>8w1UZYW7idZQ{(xM5$^ z{@v-NCkAgfW>dU~FSZ-8u~{Hs@A;Vf<{Fn?agSpRqfm%=m=Y#4n60y-TTJ#pAgW#S z0FpIyhJHAeEC>={NBeu8lAa0G$~CElU{c3$yz~>-IOmD?Mp>5l{gUF=r7KD6o6BWN z0|l1&eL_`XCbQrUG2)GK`;gEG2N#R1Aq~stvKb{!Nog;IAI1Q{xB5o1wy2OBNH}rD=-U$c(j~?r>+2`B)*PBQRp;792HXH$e=7HhcsumD^eFK1t|>_O z2rdo!bF#{EJ{DP)?)Tb}=;KOjSSgc~l+@7gbZ^Vt7J@Ubbj_m6x8}$Xsc%#r`LZAB z?b_DH2wTs5r8lv#nCYQ=7TSlH|5Pu>^n6;6A~QK*B{t~+Kql?x=erNGO8#;h2N!6L_Ob5ss_}AjiMkHgGK5JYPm~>?lDOktW!Je=Zh97 zJKDNlJ;9=yWr?|X#?ZjM+z5KTt1aKFUezX*8JNOCYOaEcOV`_bKV2dnuDcubf1BkM za-7y;i!-C~@}Fz~OY#H@&%{da$ky32G-*fuOE2;YQI#(V+LF+H1H=@2>`ctA_el2z z;WwAxL}KNI?${cqxB4z`H>0KZd9~nC9>m7$D6MDAw%D>2bUB{&p3N;CeSIk>`&QBs z`$@rj5&~Ssx=V*kxl_f?Evm^849*hZ5ekxzp?kT)s5T7eR(d%wr3__#no~yMAKZ4$ zA!(S-uX_w?BesdNYwM}WF?C}?&+gg7#UvP)ruKT$QLdnJmX{~$WouR&M;MYPjHPw! z@_&S=)sLH|8j)PI5aFcRAd@-tK;T6Al7Y7+7XfOwN+oT#*a0;KmIC&euZ@eh<>U_v zv`&%D(f!GIw+XPdb`SpMfLiG2>at){LP-Z}MVBtkKw_(om%G#C>=9m%MZaMhtdxH- zQ>J=|305f89+D#e2E**)Bqp%6$YTx7BQVe8Uvohg>OiDK96{L9!k8rgM~#!iTU{&Ns2KOlYJ;`=^U@)VX&DEH6LJJY##&( zd2qB0RmRX5NMCwMVF@r}Ix2w==TS)_6+)0<;H_6aVvM+{>{4da(5fO*yygAQL0ROAA#?aK;^57MYa6I8_4?0L+ z